FunctionSet.java

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package org.apache.doris.catalog;

import org.apache.doris.analysis.ArithmeticExpr;
import org.apache.doris.analysis.BinaryPredicate;
import org.apache.doris.analysis.CastExpr;
import org.apache.doris.analysis.CompoundPredicate;
import org.apache.doris.analysis.FunctionCallExpr;
import org.apache.doris.analysis.InPredicate;
import org.apache.doris.analysis.IsNullPredicate;
import org.apache.doris.analysis.LikePredicate;
import org.apache.doris.analysis.MatchPredicate;
import org.apache.doris.builtins.ScalarBuiltins;
import org.apache.doris.catalog.Function.NullableMode;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.SessionVariable;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class FunctionSet<T> {
    private static final Logger LOG = LogManager.getLogger(FunctionSet.class);

    // All of the registered user functions. The key is the user facing name (e.g. "myUdf"),
    // and the values are all the overloaded variants (e.g. myUdf(double), myUdf(string))
    // This includes both UDFs and UDAs. Updates are made thread safe by synchronizing
    // on this map. Functions are sorted in a canonical order defined by
    // FunctionResolutionOrder.
    private final HashMap<String, List<Function>> vectorizedFunctions;
    private final HashMap<String, List<Function>> tableFunctions;
    // For most build-in functions, it will return NullLiteral when params contain NullLiteral.
    // But a few functions need to handle NullLiteral differently, such as "if". It need to add
    // an attribute to LiteralExpr to mark null and check the attribute to decide whether to
    // replace the result with NullLiteral when function finished. It leaves to be realized.
    // Functions in this set is defined in `gensrc/script/doris_builtins_functions.py`,
    // and will be built automatically.

    private ImmutableSet<String> nullResultWithOneNullParamFunctions;

    // Including now(), curdate(), etc..
    private ImmutableSet<String> nondeterministicFunctions;

    private HashSet<String> aggFunctionNames = new HashSet<>();

    private boolean inited = false;

    public FunctionSet() {
        vectorizedFunctions = Maps.newHashMap();
        tableFunctions = Maps.newHashMap();
    }

    public void init() {
        // Populate all aggregate builtins.
        initAggregateBuiltins();

        ArithmeticExpr.initBuiltins(this);
        BinaryPredicate.initBuiltins(this);
        CompoundPredicate.initBuiltins(this);
        CastExpr.initBuiltins(this);

        IsNullPredicate.initBuiltins(this);
        ScalarBuiltins.initBuiltins(this);
        LikePredicate.initBuiltins(this);
        MatchPredicate.initBuiltins(this);
        InPredicate.initBuiltins(this);
        AliasFunction.initBuiltins(this);

        // init table function
        initTableFunction();

        inited = true;
    }

    public void buildNullResultWithOneNullParamFunction(Set<String> funcNames) {
        ImmutableSet.Builder<String> setBuilder = new ImmutableSet.Builder<String>();
        for (String funcName : funcNames) {
            setBuilder.add(funcName);
        }
        this.nullResultWithOneNullParamFunctions = setBuilder.build();
    }

    public void buildNondeterministicFunctions(Set<String> funcNames) {
        ImmutableSet.Builder<String> setBuilder = new ImmutableSet.Builder<String>();
        for (String funcName : funcNames) {
            setBuilder.add(funcName);
        }
        this.nondeterministicFunctions = setBuilder.build();
    }

    public boolean isNondeterministicFunction(String funcName) {
        return nondeterministicFunctions.contains(funcName);
    }

    public boolean isNullResultWithOneNullParamFunctions(String funcName) {
        return nullResultWithOneNullParamFunctions.contains(funcName);
    }

    private static final Map<Type, Type> MULTI_DISTINCT_SUM_RETURN_TYPE =
             ImmutableMap.<Type, Type>builder()
                    .put(Type.TINYINT, Type.BIGINT)
                    .put(Type.SMALLINT, Type.BIGINT)
                    .put(Type.INT, Type.BIGINT)
                    .put(Type.BIGINT, Type.BIGINT)
                    .put(Type.FLOAT, Type.DOUBLE)
                    .put(Type.DOUBLE, Type.DOUBLE)
                    .put(Type.LARGEINT, Type.LARGEINT)
                    .put(Type.MAX_DECIMALV2_TYPE, Type.MAX_DECIMALV2_TYPE)
                    .put(Type.DECIMAL32, Type.DECIMAL32)
                    .put(Type.DECIMAL64, Type.DECIMAL64)
                    .put(Type.DECIMAL128, Type.DECIMAL128)
                    .build();

    private static final Map<Type, Type> STDDEV_RETTYPE_SYMBOL =
            ImmutableMap.<Type, Type>builder()
                    .put(Type.TINYINT, Type.DOUBLE)
                    .put(Type.SMALLINT, Type.DOUBLE)
                    .put(Type.INT, Type.DOUBLE)
                    .put(Type.BIGINT, Type.DOUBLE)
                    .put(Type.FLOAT, Type.DOUBLE)
                    .put(Type.DOUBLE, Type.DOUBLE)
                    .put(Type.MAX_DECIMALV2_TYPE, Type.MAX_DECIMALV2_TYPE)
                    .put(Type.DECIMAL32, Type.DECIMAL32)
                    .put(Type.DECIMAL64, Type.DECIMAL64)
                    .put(Type.DECIMAL128, Type.DECIMAL128)
                    .build();

    public static final Set<String> nonDeterministicFunctions =
            ImmutableSet.<String>builder()
                    .add("RAND")
                    .add("RANDOM")
                    .add("RANDOM_BYTES")
                    .add("CONNECTION_ID")
                    .add("DATABASE")
                    .add("USER")
                    .add("UUID")
                    .add("CURRENT_USER")
                    .add("UUID_NUMERIC")
                    .build();

    public static final Set<String> nonDeterministicTimeFunctions =
            ImmutableSet.<String>builder()
                    .add("NOW")
                    .add("CURDATE")
                    .add("CURRENT_DATE")
                    .add("UTC_TIMESTAMP")
                    .add("CURTIME")
                    .add("CURRENT_TIMESTAMP")
                    .add("CURRENT_TIME")
                    .add("UNIX_TIMESTAMP")
                    .add()
                    .build();

    private static final Map<Type, String> STDDEV_UPDATE_SYMBOL =
            ImmutableMap.<Type, String>builder()
                .put(Type.TINYINT,
                        "16knuth_var_updateIN9doris_udf10TinyIntValEEEvPNS2_15FunctionContextERKT_PNS2_9StringValE")
                .put(Type.SMALLINT,
                        "16knuth_var_updateIN9doris_udf11SmallIntValEEEvPNS2_15FunctionContextERKT_PNS2_9StringValE")
                .put(Type.INT,
                        "16knuth_var_updateIN9doris_udf6IntValEEEvPNS2_15FunctionContextERKT_PNS2_9StringValE")
                .put(Type.BIGINT,
                        "16knuth_var_updateIN9doris_udf9BigIntValEEEvPNS2_15FunctionContextERKT_PNS2_9StringValE")
                .put(Type.FLOAT,
                        "16knuth_var_updateIN9doris_udf8FloatValEEEvPNS2_15FunctionContextERKT_PNS2_9StringValE")
                .put(Type.DOUBLE,
                        "16knuth_var_updateIN9doris_udf9DoubleValEEEvPNS2_15FunctionContextERKT_PNS2_9StringValE")
                .put(Type.MAX_DECIMALV2_TYPE,
                        "16knuth_var_updateEPN9doris_udf15FunctionContextERKNS1_12DecimalV2ValEPNS1_9StringValE")
                .build();

    public static final String HLL_HASH = "hll_hash";
    public static final String HLL_UNION = "hll_union";
    public static final String HLL_UNION_AGG = "hll_union_agg";
    public static final String HLL_RAW_AGG = "hll_raw_agg";
    public static final String HLL_CARDINALITY = "hll_cardinality";
    public static final String HLL_FROM_BASE64 = "hll_from_base64";

    public static final String TO_BITMAP = "to_bitmap";
    public static final String TO_BITMAP_WITH_CHECK = "to_bitmap_with_check";
    public static final String BITMAP_HASH = "bitmap_hash";
    public static final String BITMAP_UNION = "bitmap_union";
    public static final String BITMAP_UNION_COUNT = "bitmap_union_count";
    public static final String BITMAP_UNION_INT = "bitmap_union_int";
    public static final String BITMAP_COUNT = "bitmap_count";
    public static final String INTERSECT_COUNT = "intersect_count";
    public static final String BITMAP_INTERSECT = "bitmap_intersect";
    public static final String ORTHOGONAL_BITMAP_INTERSECT = "orthogonal_bitmap_intersect";
    public static final String ORTHOGONAL_BITMAP_INTERSECT_COUNT = "orthogonal_bitmap_intersect_count";
    public static final String ORTHOGONAL_BITMAP_UNION_COUNT = "orthogonal_bitmap_union_count";
    public static final String APPROX_COUNT_DISTINCT = "approx_count_distinct";
    public static final String NDV = "ndv";
    public static final String ORTHOGONAL_BITMAP_EXPR_CALCULATE_COUNT = "orthogonal_bitmap_expr_calculate_count";
    public static final String ORTHOGONAL_BITMAP_EXPR_CALCULATE = "orthogonal_bitmap_expr_calculate";

    public static final String QUANTILE_UNION = "quantile_union";
    //TODO(weixiang): is quantile_percent can be replaced by approx_percentile?
    public static final String QUANTILE_PERCENT = "quantile_percent";
    public static final String TO_QUANTILE_STATE = "to_quantile_state";
    public static final String COLLECT_LIST = "collect_list";
    public static final String COLLECT_SET = "collect_set";
    public static final String HISTOGRAM = "histogram";
    public static final String LINEAR_HISTOGRAM = "linear_histogram";
    public static final String HIST = "hist";
    public static final String MAP_AGG = "map_agg";

    public static final String BITMAP_AGG = "bitmap_agg";
    public static final String COUNT_BY_ENUM = "count_by_enum";

    private static final Map<Type, String> TOPN_UPDATE_SYMBOL =
            ImmutableMap.<Type, String>builder()
                    .put(Type.CHAR,
                            "_ZN5doris13TopNFunctions11topn_updateIN9doris_udf9StringValEEEvPNS2_15FunctionContextERKT_RKNS2_6IntValEPS3_")
                    .put(Type.VARCHAR,
                            "_ZN5doris13TopNFunctions11topn_updateIN9doris_udf9StringValEEEvPNS2_15FunctionContextERKT_RKNS2_6IntValEPS3_")
                    .put(Type.STRING,
                            "_ZN5doris13TopNFunctions11topn_updateIN9doris_udf9StringValEEEvPNS2_15FunctionContextERKT_RKNS2_6IntValEPS3_")
                    .build();

    public Function getFunction(Function desc, Function.CompareMode mode) {
        return getFunction(desc, mode, false);
    }

    public Function getFunction(Function desc, Function.CompareMode mode, boolean isTableFunction) {
        List<Function> fns;
        if (isTableFunction) {
            fns = tableFunctions.get(desc.functionName());
        } else {
            fns = vectorizedFunctions.get(desc.functionName());
        }
        if (fns == null) {
            return null;
        }

        List<Function> normalFunctions = Lists.newArrayList();
        List<Function> templateFunctions = Lists.newArrayList();
        List<Function> variadicTemplateFunctions = Lists.newArrayList();
        List<Function> inferenceFunctions = Lists.newArrayList();
        for (Function fn : fns) {
            if (fn.isInferenceFunction()) {
                inferenceFunctions.add(fn);
                continue;
            }
            if (fn.hasTemplateArg()) {
                if (!fn.hasVariadicTemplateArg()) {
                    templateFunctions.add(fn);
                } else {
                    variadicTemplateFunctions.add(fn);
                }
            } else {
                normalFunctions.add(fn);
            }
        }

        // try normal functions first
        Function fn = getFunction(desc, mode, normalFunctions);
        if (fn != null) {
            return fn;
        }

        // then specialize template functions and try them
        List<Function> specializedTemplateFunctions = Lists.newArrayList();
        for (Function f : templateFunctions) {
            f = specializeTemplateFunction(f, desc, false);
            if (f != null) {
                specializedTemplateFunctions.add(f);
            }
        }

        // try template function second
        fn = getFunction(desc, mode, specializedTemplateFunctions);
        if (fn != null) {
            return fn;
        }

        // then specialize variadic template function and try them
        List<Function> specializedVariadicTemplateFunctions = Lists.newArrayList();
        for (Function f : variadicTemplateFunctions) {
            f = specializeTemplateFunction(f, desc, true);
            if (f != null) {
                specializedVariadicTemplateFunctions.add(f);
            }
        }

        // try variadic template function third
        fn = getFunction(desc, mode, specializedVariadicTemplateFunctions);
        if (fn != null) {
            return fn;
        }

        List<Function> inferredFunctions = Lists.newArrayList();
        for (Function f : inferenceFunctions) {
            if (f.hasTemplateArg()) {
                f = specializeTemplateFunction(f, desc, f.hasVariadicTemplateArg());
            }
            if (f != null && (f = resolveInferenceFunction(f, desc)) != null) {
                inferredFunctions.add(f);
            }
        }

        // try inference function at last
        return getFunction(desc, mode, inferredFunctions);
    }

    private Function getFunction(Function desc, Function.CompareMode mode, List<Function> fns) {
        // First check for identical
        for (Function f : fns) {
            if (f.compare(desc, Function.CompareMode.IS_IDENTICAL)) {
                return f;
            }
        }
        if (mode == Function.CompareMode.IS_IDENTICAL) {
            return null;
        }

        // Next check for indistinguishable
        for (Function f : fns) {
            if (f.compare(desc, Function.CompareMode.IS_INDISTINGUISHABLE)) {
                return f;
            }
        }
        if (mode == Function.CompareMode.IS_INDISTINGUISHABLE) {
            return null;
        }

        // Next check for strict supertypes
        for (Function f : fns) {
            if (f.compare(desc, Function.CompareMode.IS_SUPERTYPE_OF) && isCastMatchAllowed(desc, f)) {
                return f;
            }
        }
        if (mode == Function.CompareMode.IS_SUPERTYPE_OF) {
            return null;
        }

        // Finally check for non-strict supertypes
        for (Function f : fns) {
            if (f.compare(desc, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF) && isCastMatchAllowed(desc, f)) {
                return f;
            }
        }
        return null;
    }

    public Function specializeTemplateFunction(Function templateFunction, Function requestFunction, boolean isVariadic) {
        try {
            boolean hasTemplateType = false;
            if (LOG.isDebugEnabled()) {
                LOG.debug("templateFunction signature: {}, return type: {}",
                            templateFunction.signatureString(), templateFunction.getReturnType());
                if (LOG.isDebugEnabled()) {
                    LOG.debug("requestFunction signature: {}, return type: {}",
                                requestFunction.signatureString(), requestFunction.getReturnType());
                }
            }
            List<Type> newArgTypes = Lists.newArrayList();
            List<Type> newRetType = Lists.newArrayList();
            if (isVariadic) {
                Map<String, Integer> expandSizeMap = Maps.newHashMap();
                templateFunction.collectTemplateExpandSize(requestFunction.getArgs(), expandSizeMap);
                // expand the variadic template in arg types
                for (Type argType : templateFunction.getArgs()) {
                    if (argType.needExpandTemplateType()) {
                        newArgTypes.addAll(argType.expandVariadicTemplateType(expandSizeMap));
                    } else {
                        newArgTypes.add(argType);
                    }
                }

                // expand the variadic template in ret type
                if (templateFunction.getReturnType().needExpandTemplateType()) {
                    newRetType.addAll(templateFunction.getReturnType().expandVariadicTemplateType(expandSizeMap));
                    Preconditions.checkState(newRetType.size() == 1);
                } else {
                    newRetType.add(templateFunction.getReturnType());
                }
            } else {
                newArgTypes.addAll(Lists.newArrayList(templateFunction.getArgs()));
                newRetType.add(templateFunction.getReturnType());
            }
            Function specializedFunction = templateFunction;
            if (templateFunction instanceof ScalarFunction) {
                ScalarFunction f = (ScalarFunction) templateFunction;
                specializedFunction = new ScalarFunction(f.getFunctionName(), newArgTypes, newRetType.get(0), f.hasVarArgs(),
                        f.getSymbolName(), f.getBinaryType(), f.isUserVisible(), true, f.getNullableMode());
            } else {
                throw new TypeException(templateFunction
                                + " is not support for template since it's not a ScalarFunction");
            }
            ArrayList<Type> args = new ArrayList<>();
            Collections.addAll(args, specializedFunction.getArgs());
            Map<String, Type> specializedTypeMap = Maps.newHashMap();
            boolean enableDecimal256 = SessionVariable.getEnableDecimal256();
            int i = 0;
            for (; i < args.size(); i++) {
                if (args.get(i).hasTemplateType()) {
                    hasTemplateType = true;
                    // if args[i] is template type, and requestFunction.getArgs()[i] NULL_TYPE, we need call function
                    // deduce to get the specific type
                    Type deduceType = requestFunction.getArgs()[i];
                    if (requestFunction.getArgs()[i].isNull()
                            || (requestFunction.getArgs()[i] instanceof ArrayType
                            && ((ArrayType) requestFunction.getArgs()[i]).getItemType().isNull())
                            && FunctionTypeDeducers.DEDUCERS.containsKey(specializedFunction.functionName())) {
                        deduceType = FunctionTypeDeducers.deduce(specializedFunction.functionName(), i, requestFunction.getArgs());
                        args.set(i, args.get(i).specializeTemplateType(deduceType == null ? requestFunction.getArgs()[i]
                                : deduceType, specializedTypeMap, false, enableDecimal256));
                    } else {
                        args.set(i, args.get(i).specializeTemplateType(requestFunction.getArgs()[i],
                                specializedTypeMap, false, enableDecimal256));
                    }
                }
            }
            specializedFunction.setArgs(args);
            if (specializedFunction.getReturnType().hasTemplateType()) {
                hasTemplateType = true;
                specializedFunction.setReturnType(
                        specializedFunction.getReturnType().specializeTemplateType(
                        requestFunction.getReturnType(), specializedTypeMap, true, enableDecimal256));
            }
            if (LOG.isDebugEnabled()) {
                LOG.debug("specializedFunction signature: {}, return type: {}",
                            specializedFunction.signatureString(), specializedFunction.getReturnType());
            }
            return hasTemplateType ? specializedFunction : templateFunction;
        } catch (TypeException e) {
            if (inited && LOG.isDebugEnabled()) {
                LOG.debug("specializeTemplateFunction exception", e);
            }
            return null;
        }
    }

    public Function resolveInferenceFunction(Function inferenceFunction, Function requestFunction) {
        Type[] inputArgs = requestFunction.getArgs();
        Type[] inferArgs = inferenceFunction.getArgs();
        Type[] newTypes = Arrays.copyOf(inputArgs, inputArgs.length);
        for (int i = 0; i < inferArgs.length; ++i) {
            Type inferType = inferArgs[i];
            Type inputType = inputArgs[i];
            if (!inferType.isAnyType()) {
                newTypes[i] = inputType;
            }
        }
        Type newRetType = FunctionTypeDeducers.deduce(inferenceFunction.functionName(), 0, newTypes);
        if (newRetType != null && inferenceFunction instanceof ScalarFunction) {
            ScalarFunction f = (ScalarFunction) inferenceFunction;
            return new ScalarFunction(f.getFunctionName(), Lists.newArrayList(newTypes), newRetType, f.hasVarArgs(),
                    f.getSymbolName(), f.getBinaryType(), f.isUserVisible(), true, f.getNullableMode());
        }
        return null;
    }

    /**
     * There are essential differences in the implementation of some functions for different
     * types params, which should be prohibited.
     * @param desc
     * @param candicate
     * @return
     */
    public static boolean isCastMatchAllowed(Function desc, Function candicate) {
        final String functionName = desc.getFunctionName().getFunction();
        final Type[] descArgTypes = desc.getArgs();
        final Type[] candicateArgTypes = candicate.getArgs();
        if (!(descArgTypes[0] instanceof ScalarType)
                || !(candicateArgTypes[0] instanceof ScalarType)) {
            if (candicateArgTypes[0] instanceof ArrayType) {
                // match is exactly type. but for null type , with in array|map elem can not return true, because for
                // be will make null_type to uint8
                // so here meet null_type just make true as allowed, descArgTypes[0]).getItemType().isNull() is for
                // empty literal like: []|{}
                if (descArgTypes[0] instanceof ArrayType && ((ArrayType) descArgTypes[0]).getItemType().isNull()) {
                    return true;
                }
                return descArgTypes[0].matchesType(candicateArgTypes[0]);
            } else if (candicateArgTypes[0] instanceof MapType) {
                if (descArgTypes[0] instanceof MapType && ((MapType) descArgTypes[0]).getKeyType().isNull()
                        && ((MapType) descArgTypes[0]).getValueType().isNull()) {
                    return true;
                }
                return descArgTypes[0].matchesType(candicateArgTypes[0]);
            }
            return false;
        }
        final ScalarType descArgType = (ScalarType) descArgTypes[0];
        final ScalarType candicateArgType = (ScalarType) candicateArgTypes[0];
        if (functionName.equalsIgnoreCase("hex")
                || functionName.equalsIgnoreCase("greast")
                || functionName.equalsIgnoreCase("least")
                || functionName.equalsIgnoreCase("lead")
                || functionName.equalsIgnoreCase("lag")) {
            if (!descArgType.isStringType() && candicateArgType.isStringType()) {
                // The implementations of hex for string and int are different.
                return false;
            }
        }
        if (FunctionCallExpr.STRING_SEARCH_FUNCTION_SET.contains(desc.functionName())) {
            if (descArgTypes[1].isStringType() && candicateArgTypes[1].isArrayType()) {
                // The needles arg of search functions should not be allowed to cast from string.
                return false;
            }
        }
        // If set `roundPreciseDecimalV2Value`, only use decimalv3 as target type to execute round function
        if (ConnectContext.get() != null
                && ConnectContext.get().getSessionVariable().roundPreciseDecimalV2Value
                && FunctionCallExpr.ROUND_FUNCTION_SET.contains(desc.functionName())
                && descArgType.isDecimalV2()) {
            return candicateArgType.getPrimitiveType() == PrimitiveType.DECIMAL128;
        }
        if ((descArgType.isDecimalV3() && candicateArgType.isDecimalV2())
                || (descArgType.isDecimalV2() && candicateArgType.isDecimalV3())) {
            return false;
        }
        return true;
    }

    public Function getFunction(String signatureString, boolean vectorized) {
        for (List<Function> fns : vectorizedFunctions.values()) {
            for (Function f : fns) {
                if (f.signatureString().equals(signatureString)) {
                    return f;
                }
            }
        }
        return null;
    }

    private boolean addFunction(Function fn, boolean isBuiltin) {
        if (fn instanceof AggregateFunction) {
            aggFunctionNames.add(fn.functionName());
        }

        // TODO: add this to persistent store
        if (getFunction(fn, Function.CompareMode.IS_INDISTINGUISHABLE) != null) {
            return false;
        }
        List<Function> fns = vectorizedFunctions.get(fn.functionName());
        if (fns == null) {
            fns = Lists.newArrayList();
            vectorizedFunctions.put(fn.functionName(), fns);
        }
        fns.add(fn);
        return true;
    }

    /**
     * Add a builtin with the specified name and signatures to this db.
     */
    public void addScalarBuiltin(String fnName, String symbol, boolean userVisible,
                                 String prepareFnSymbol, String closeFnSymbol,
                                 Function.NullableMode nullableMode, Type retType,
                                 boolean varArgs, Type ... args) {
        ArrayList<Type> argsType = new ArrayList<Type>();
        for (Type type : args) {
            argsType.add(type);
        }
        addBuiltin(ScalarFunction.createBuiltin(
                fnName, retType, nullableMode, argsType, varArgs,
                symbol, prepareFnSymbol, closeFnSymbol, userVisible));
    }

    public void addScalarAndVectorizedBuiltin(String fnName, boolean userVisible,
            Function.NullableMode nullableMode, Type retType,
            boolean varArgs, Type ... args) {
        ArrayList<Type> argsType = new ArrayList<Type>();
        for (Type type : args) {
            argsType.add(type);
        }
        addBuiltinBothScalaAndVectorized(ScalarFunction.createBuiltin(
                fnName, retType, nullableMode, argsType, varArgs,
                "", "", "", userVisible));
    }

    /**
     * Adds a builtin to this database. The function must not already exist.
     */
    public void addBuiltin(Function fn) {
        addFunction(fn, true);
    }

    /**
     * Adds a function both in FunctionSet and VecFunctionSet to this database.
     * The function must not already exist and need to be not vectorized
     */
    public void addBuiltinBothScalaAndVectorized(Function fn) {
        if (getFunction(fn, Function.CompareMode.IS_INDISTINGUISHABLE) != null) {
            return;
        }

        // add vectorized function
        List<Function> vecFns = vectorizedFunctions.get(fn.functionName());
        if (vecFns == null) {
            vecFns = Lists.newArrayList();
            vectorizedFunctions.put(fn.functionName(), vecFns);
        }
        vecFns.add(fn);
    }


    public static final String COUNT = "count";
    public static final String WINDOW_FUNNEL = "window_funnel";

    public static final String RETENTION = "retention";

    public static final String REGR_INTERCEPT = "regr_intercept";

    public static final String REGR_SLOPE = "regr_slope";

    public static final String SEQUENCE_MATCH = "sequence_match";

    public static final String SEQUENCE_COUNT = "sequence_count";

    public static final String GROUP_UNIQ_ARRAY = "group_uniq_array";

    public static final String GROUP_ARRAY = "group_array";

    public static final String GROUP_ARRAY_INTERSECT = "group_array_intersect";

    public static final String ARRAY_AGG = "array_agg";

    public static final String SUM0 = "sum0";

    public static final String MULTI_DISTINCT_SUM0 = "multi_distinct_sum0";

    // Populate all the aggregate builtins in the catalog.
    // null symbols indicate the function does not need that step of the evaluation.
    // An empty symbol indicates a TODO for the BE to implement the function.
    private void initAggregateBuiltins() {

        // Type stringType[] = {Type.CHAR, Type.VARCHAR};
        // count(*)
        // vectorized
        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.COUNT,
                new ArrayList<Type>(), Type.BIGINT, Type.BIGINT,
                "",
                "",
                "",
                null, null,
                "",
                null, false, true, true, true));

        // regr_intercept
        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.REGR_INTERCEPT,
                Lists.newArrayList(Type.DOUBLE, Type.DOUBLE), Type.DOUBLE, Type.DOUBLE,
                "",
                "",
                "",
                null, null,
                "",
                null, false, false, false, true));
        // regr_slope
        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.REGR_SLOPE,
                Lists.newArrayList(Type.DOUBLE, Type.DOUBLE), Type.DOUBLE, Type.DOUBLE,
                "",
                "",
                "",
                null, null,
                "",
                null, false, false, false, true));

        // count(array/map/struct)
        for (Type complexType : Lists.newArrayList(Type.ARRAY, Type.MAP, Type.GENERIC_STRUCT)) {
            addBuiltin(AggregateFunction.createBuiltin(FunctionSet.COUNT,
                    Lists.newArrayList(complexType), Type.BIGINT, Type.BIGINT,
                    "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, true, true));

            addBuiltin(AggregateFunction.createBuiltin(FunctionSet.COUNT,
                    Lists.newArrayList(complexType), Type.BIGINT, Type.BIGINT,
                    "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, true, true));
        }

        // Vectorization does not need symbol any more, we should clean it in the future.
        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.WINDOW_FUNNEL,
                Lists.newArrayList(Type.BIGINT, Type.STRING, Type.DATETIME, Type.BOOLEAN),
                Type.INT,
                Type.VARCHAR,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));
        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.WINDOW_FUNNEL,
                Lists.newArrayList(Type.BIGINT, Type.STRING, Type.DATETIMEV2, Type.BOOLEAN),
                Type.INT,
                Type.VARCHAR,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        // retention vectorization
        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.RETENTION,
                Lists.newArrayList(Type.BOOLEAN),
                new ArrayType(Type.BOOLEAN),
                Type.VARCHAR,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        // sequenceMatch
        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.SEQUENCE_MATCH,
                Lists.newArrayList(Type.STRING, Type.DATEV2, Type.BOOLEAN),
                Type.BOOLEAN,
                Type.VARCHAR,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.SEQUENCE_MATCH,
                Lists.newArrayList(Type.STRING, Type.DATETIME, Type.BOOLEAN),
                Type.BOOLEAN,
                Type.VARCHAR,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.SEQUENCE_MATCH,
                Lists.newArrayList(Type.STRING, Type.DATETIMEV2, Type.BOOLEAN),
                Type.BOOLEAN,
                Type.VARCHAR,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        // sequenceCount
        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.SEQUENCE_COUNT,
                Lists.newArrayList(Type.STRING, Type.DATEV2, Type.BOOLEAN),
                Type.BIGINT,
                Type.VARCHAR,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.SEQUENCE_COUNT,
                Lists.newArrayList(Type.STRING, Type.DATETIME, Type.BOOLEAN),
                Type.BIGINT,
                Type.VARCHAR,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        addBuiltin(AggregateFunction.createBuiltin(FunctionSet.SEQUENCE_COUNT,
                Lists.newArrayList(Type.STRING, Type.DATETIMEV2, Type.BOOLEAN),
                Type.BIGINT,
                Type.VARCHAR,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        addBuiltin(AggregateFunction.createBuiltin("hll_union_agg",
                        Lists.newArrayList(Type.HLL), Type.BIGINT, Type.VARCHAR,
                        "",
                        "",
                        "",
                        "",
                        "",
                        null,
                        "",
                        true, true, true, true));
        addBuiltin(AggregateFunction.createBuiltin(HLL_UNION,
                        Lists.newArrayList(Type.HLL), Type.HLL, Type.HLL,
                        "",
                        "",
                        "",
                        "",
                        "",
                        true, false, true, true));
        addBuiltin(AggregateFunction.createBuiltin("hll_raw_agg",
                        Lists.newArrayList(Type.HLL), Type.HLL, Type.HLL,
                        "",
                        "",
                        "",
                        "",
                        "",
                        true, false, true, true));

        for (Type t : Type.getTrivialTypes()) {
            if (t.isNull()) {
                continue; // NULL is handled through type promotion.
            }
            if (t.isScalarType(PrimitiveType.CHAR)) {
                continue; // promoted to STRING
            }
            // Count
            // vectorized
            addBuiltin(AggregateFunction.createBuiltin(FunctionSet.COUNT,
                    Lists.newArrayList(t), Type.BIGINT, Type.BIGINT,
                    "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, true, true));

            // count in multi distinct
            if (t.equals(Type.CHAR) || t.equals(Type.VARCHAR)) {
                // vectorized
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_count", Lists.newArrayList(t),
                        Type.BIGINT,
                        Type.VARCHAR,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            } else if (t.equals(Type.STRING)) {
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_count", Lists.newArrayList(t),
                        Type.BIGINT,
                        Type.STRING,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            } else if (t.equals(Type.TINYINT) || t.equals(Type.SMALLINT) || t.equals(Type.INT)
                    || t.equals(Type.BIGINT) || t.equals(Type.LARGEINT) || t.equals(Type.DOUBLE)) {
                // vectorized
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_count", Lists.newArrayList(t),
                        Type.BIGINT,
                        t,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            } else if (t.equals(Type.DATE) || t.equals(Type.DATETIME)) {
                // now we don't support datetime distinct
            } else if (t.equals(Type.MAX_DECIMALV2_TYPE)) {
                // vectorized
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_count", Lists.newArrayList(t),
                        Type.BIGINT,
                        Type.MAX_DECIMALV2_TYPE,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            } else if (t.equals(Type.DECIMAL32)) {
                // vectorized
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_count", Lists.newArrayList(t),
                        Type.BIGINT,
                        Type.DECIMAL32,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            } else if (t.equals(Type.DECIMAL64)) {
                // vectorized
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_count", Lists.newArrayList(t),
                        Type.BIGINT,
                        Type.DECIMAL64,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            } else if (t.equals(Type.DECIMAL128)) {
                // vectorized
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_count", Lists.newArrayList(t),
                        Type.BIGINT,
                        Type.DECIMAL128,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            }

            // sum in multi distinct
            if (t.equals(Type.BIGINT) || t.equals(Type.LARGEINT) || t.equals(Type.DOUBLE)) {
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum", Lists.newArrayList(t),
                        t,
                        t,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum0", Lists.newArrayList(t),
                        t,
                        t,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            }  else if (t.equals(Type.MAX_DECIMALV2_TYPE)) {
                // vectorized
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum", Lists.newArrayList(t),
                        MULTI_DISTINCT_SUM_RETURN_TYPE.get(t),
                        Type.MAX_DECIMALV2_TYPE,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum0", Lists.newArrayList(t),
                        MULTI_DISTINCT_SUM_RETURN_TYPE.get(t),
                        Type.MAX_DECIMALV2_TYPE,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            } else if (t.equals(Type.DECIMAL32)) {
                // vectorized
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum", Lists.newArrayList(t),
                        MULTI_DISTINCT_SUM_RETURN_TYPE.get(t),
                        Type.DECIMAL32,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum0", Lists.newArrayList(t),
                        MULTI_DISTINCT_SUM_RETURN_TYPE.get(t),
                        Type.DECIMAL32,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            } else if (t.equals(Type.DECIMAL64)) {
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum", Lists.newArrayList(t),
                        MULTI_DISTINCT_SUM_RETURN_TYPE.get(t),
                        Type.DECIMAL64,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum0", Lists.newArrayList(t),
                        MULTI_DISTINCT_SUM_RETURN_TYPE.get(t),
                        Type.DECIMAL64,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            } else if (t.equals(Type.DECIMAL128)) {
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum", Lists.newArrayList(t),
                        MULTI_DISTINCT_SUM_RETURN_TYPE.get(t),
                        Type.DECIMAL128,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_sum0", Lists.newArrayList(t),
                        MULTI_DISTINCT_SUM_RETURN_TYPE.get(t),
                        Type.DECIMAL128,
                        "",
                        "",
                        "",
                        "",
                        null,
                        null,
                        "",
                        false, true, true, true));
            }
            // Min
            addBuiltin(AggregateFunction.createBuiltin("min",
                    Lists.newArrayList(t), t, t, "",
                    "",
                    "",
                    null, null,
                    null, null, true, true, false, true));

            // Max
            addBuiltin(AggregateFunction.createBuiltin("max",
                    Lists.newArrayList(t), t, t, "",
                    "",
                    "",
                    null, null,
                    null, null, true, true, false, true));

            // Any
            addBuiltin(AggregateFunction.createBuiltin("any", Lists.newArrayList(t), t, t, null, null, null, null, null,
                    null, null, true, false, false, true));
            // Any_Value
            addBuiltin(AggregateFunction.createBuiltin("any_value", Lists.newArrayList(t), t, t, null, null, null, null,
                    null, null, null, true, false, false, true));

            // vectorized
            for (Type kt : Type.getTrivialTypes()) {
                if (kt.isNull()) {
                    continue;
                }
                addBuiltin(AggregateFunction.createBuiltin("max_by", Lists.newArrayList(t, kt), t, Type.VARCHAR,
                        "", "", "", "", "", null, "",
                        true, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("min_by", Lists.newArrayList(t, kt), t, Type.VARCHAR,
                        "", "", "", "", "", null, "",
                        true, true, false, true));
            }

            // vectorized
            addBuiltin(AggregateFunction.createBuiltin("ndv", Lists.newArrayList(t), Type.BIGINT, Type.VARCHAR,
                            "",
                            "",
                            "",
                            "",
                            "",
                            true, true, true, true));

            // vectorized
            addBuiltin(AggregateFunction.createBuiltin("approx_count_distinct", Lists.newArrayList(t), Type.BIGINT,
                            Type.VARCHAR,
                            "",
                            "",
                            "",
                            "",
                            "",
                            true, true, true, true));

            // vectorized
            addBuiltin(AggregateFunction.createBuiltin(BITMAP_UNION_INT,
                    Lists.newArrayList(t), Type.BIGINT, t,
                    "",
                    "",
                    "",
                    "",
                    "",
                    true, false, true, true));

            // VEC_INTERSECT_COUNT
            addBuiltin(
                    AggregateFunction.createBuiltin(INTERSECT_COUNT, Lists.newArrayList(Type.BITMAP, t, t), Type.BIGINT,
                            Type.VARCHAR, true, "",
                            "", "",
                            "", null, null,
                            "", true, false, true, true));

            // TopN
            if (TOPN_UPDATE_SYMBOL.containsKey(t)) {
                // vectorized
                addBuiltin(AggregateFunction.createBuiltin("topn", Lists.newArrayList(t, Type.INT), Type.VARCHAR,
                        Type.VARCHAR,
                        "",
                        "",
                        "",
                        "",
                        "",
                        true, false, true, true));
                addBuiltin(AggregateFunction.createBuiltin("topn", Lists.newArrayList(t, Type.INT, Type.INT),
                        Type.VARCHAR, Type.VARCHAR,
                        "",
                        "",
                        "",
                        "",
                        "",
                        true, false, true, true));
            }

            if (!Type.JSONB.equals(t)) {
                for (Type valueType : Type.getMapSubTypes()) {
                    addBuiltin(AggregateFunction.createBuiltin(MAP_AGG, Lists.newArrayList(t, valueType),
                            new MapType(t, valueType),
                            Type.VARCHAR,
                            "", "", "", "", "", null, "",
                            true, true, false, true));
                }

                for (Type v : Type.getArraySubTypes()) {
                    addBuiltin(AggregateFunction.createBuiltin(MAP_AGG, Lists.newArrayList(t, new ArrayType(v)),
                            new MapType(t, new ArrayType(v)),
                            new MapType(t, new ArrayType(v)),
                            "", "", "", "", "", null, "",
                            true, true, false, true));
                }
            }

            if (STDDEV_UPDATE_SYMBOL.containsKey(t)) {
                //vec stddev stddev_samp stddev_pop
                addBuiltin(AggregateFunction.createBuiltin("stddev",
                        Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), t,
                        "",
                        "",
                        "",
                        null, null, null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("stddev_samp",
                        Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), t,
                        "",
                        "",
                        "",
                        null, null, null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("stddev_pop",
                        Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), t,
                        "",
                        "",
                        "",
                        null, null, null,
                        "",
                        false, true, false, true));

                //vec: variance variance_samp var_samp variance_pop var_pop
                addBuiltin(AggregateFunction.createBuiltin("variance",
                        Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), t,
                        "",
                        "",
                        "",
                        null, null, null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("variance_pop",
                        Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), t,
                        "",
                        "",
                        "",
                        null, null, null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("var_pop",
                        Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), t,
                        "",
                        "",
                        "",
                        null, null, null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("variance_samp",
                        Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), t,
                        "",
                        "",
                        "",
                        null, null, null,
                        "",
                        false, true, false, true));
                addBuiltin(AggregateFunction.createBuiltin("var_samp",
                        Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), t,
                        "",
                        "",
                        "",
                        null, null, null,
                        "",
                        false, true, false, true));

                addBuiltin(AggregateFunction.createBuiltin("avg_weighted",
                        Lists.<Type>newArrayList(t, Type.DOUBLE), Type.DOUBLE, Type.DOUBLE,
                        "", "", "", "", "", "", "",
                        false, true, false, true));
            }
        }

        // Sum
        // functionName(String) -> returnsNonNullOnEmpty(Boolean)
        Map<String, Boolean> sumNames = ImmutableMap.of(
                "sum", false,
                "sum_distinct", false,
                "sum0", true
        );
        for (Entry<String, Boolean> nameWithReturn : sumNames.entrySet()) {
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.BOOLEAN), Type.BIGINT, Type.BIGINT, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));

            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.TINYINT), Type.BIGINT, Type.BIGINT, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.SMALLINT), Type.BIGINT, Type.BIGINT, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.INT), Type.BIGINT, Type.BIGINT, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.BIGINT), Type.BIGINT, Type.BIGINT, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.DOUBLE), Type.DOUBLE, Type.DOUBLE, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.MAX_DECIMALV2_TYPE), Type.MAX_DECIMALV2_TYPE, Type.MAX_DECIMALV2_TYPE, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.DECIMAL32), ScalarType.DECIMAL128, Type.DECIMAL128, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.DECIMAL64), Type.DECIMAL128, Type.DECIMAL128, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.DECIMAL128), Type.DECIMAL128, Type.DECIMAL128, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
            addBuiltin(AggregateFunction.createBuiltin(nameWithReturn.getKey(),
                    Lists.<Type>newArrayList(Type.LARGEINT), Type.LARGEINT, Type.LARGEINT, "",
                    "",
                    "",
                    null, null,
                    "",
                    null, false, true, nameWithReturn.getValue(), true));
        }

        Type[] types = {Type.SMALLINT, Type.TINYINT, Type.INT, Type.BIGINT, Type.FLOAT, Type.DOUBLE, Type.CHAR,
                Type.VARCHAR, Type.STRING};
        for (Type t : types) {
            //vec ORTHOGONAL_BITMAP_INTERSECT and ORTHOGONAL_BITMAP_INTERSECT_COUNT
            addBuiltin(
                    AggregateFunction.createBuiltin(ORTHOGONAL_BITMAP_INTERSECT, Lists.newArrayList(Type.BITMAP, t, t),
                            Type.BITMAP, Type.BITMAP, true, "", "", "", "", "", "", "", true, false, true, true));

            addBuiltin(AggregateFunction.createBuiltin(ORTHOGONAL_BITMAP_INTERSECT_COUNT,
                    Lists.newArrayList(Type.BITMAP, t, t), Type.BIGINT, Type.BITMAP, true, "", "", "", "", "", "", "",
                    true, false, true, true));
        }

        Type[] ntypes = {Type.CHAR, Type.VARCHAR, Type.STRING};
        for (Type t : ntypes) {
            //vec ORTHOGONAL_BITMAP_EXPR_CALCULATE and ORTHOGONAL_BITMAP_EXPR_CALCULATE_COUNT
            addBuiltin(
                    AggregateFunction.createBuiltin(ORTHOGONAL_BITMAP_EXPR_CALCULATE, Lists.newArrayList(Type.BITMAP, t, Type.STRING),
                            Type.BITMAP, Type.BITMAP, true, "", "", "", "", "", "", "", true, false, true, true));

            addBuiltin(AggregateFunction.createBuiltin(ORTHOGONAL_BITMAP_EXPR_CALCULATE_COUNT,
                    Lists.newArrayList(Type.BITMAP, t, Type.STRING), Type.BIGINT, Type.BITMAP, true, "", "", "", "", "", "", "",
                    true, false, true, true));
        }

        addBuiltin(AggregateFunction.createBuiltin(BITMAP_UNION, Lists.newArrayList(Type.BITMAP),
                Type.BITMAP,
                Type.BITMAP,
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));
        addBuiltin(AggregateFunction.createBuiltin(BITMAP_UNION_COUNT, Lists.newArrayList(Type.BITMAP),
                Type.BIGINT,
                Type.BITMAP,
                "",
                "",
                "",
                "",
                "",
                null,
                "",
                true, true, true, true));
        // ORTHOGONAL_BITMAP_UNION_COUNT vectorized
        addBuiltin(AggregateFunction.createBuiltin(ORTHOGONAL_BITMAP_UNION_COUNT, Lists.newArrayList(Type.BITMAP),
                Type.BIGINT, Type.BITMAP, "", "", "", "", null, null, "", true, true, true, true));

        addBuiltin(AggregateFunction.createBuiltin(BITMAP_INTERSECT, Lists.newArrayList(Type.BITMAP),
                Type.BITMAP, Type.BITMAP,
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        // vec group_bitmap_xor
        addBuiltin(AggregateFunction.createBuiltin("group_bitmap_xor", Lists.newArrayList(Type.BITMAP),
                Type.BITMAP, Type.BITMAP,
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));
        //group_bit_function
        for (Type t : Type.getIntegerTypes()) {
            addBuiltin(AggregateFunction.createBuiltin("group_bit_or",
                    Lists.newArrayList(t), t, t, "", "", "", "", "",
                    false, true, false, true));
            addBuiltin(AggregateFunction.createBuiltin("group_bit_and",
                    Lists.newArrayList(t), t, t, "", "", "", "", "",
                    false, true, false, true));
            addBuiltin(AggregateFunction.createBuiltin("group_bit_xor",
                    Lists.newArrayList(t), t, t, "", "", "", "", "",
                    false, true, false, true));
            if (!t.equals(Type.LARGEINT)) {
                addBuiltin(
                        AggregateFunction.createBuiltin("bitmap_agg", Lists.newArrayList(t), Type.BITMAP, Type.BITMAP,
                                "",
                                "",
                                "",
                                "",
                                "",
                                true, false, true, true));
            }
        }

        addBuiltin(AggregateFunction.createBuiltin(QUANTILE_UNION, Lists.newArrayList(Type.QUANTILE_STATE),
                Type.QUANTILE_STATE,
                Type.QUANTILE_STATE,
                "",
                "",
                "",
                "",
                "",
                true, false, true, true));

        //vec percentile and percentile_approx
        addBuiltin(AggregateFunction.createBuiltin("percentile",
                        Lists.newArrayList(Type.BIGINT, Type.DOUBLE), Type.DOUBLE, Type.VARCHAR,
                        "",
                        "",
                        "",
                        "",
                        "",
                        false, true, false, true));

        addBuiltin(AggregateFunction.createBuiltin("percentile_cont",
                        Lists.newArrayList(Type.BIGINT, Type.DOUBLE), Type.DOUBLE, Type.VARCHAR,
                        "",
                        "",
                        "",
                        "",
                        "",
                        false, true, false, true));

        addBuiltin(AggregateFunction.createBuiltin("percentile_approx",
                Lists.<Type>newArrayList(Type.DOUBLE, Type.DOUBLE), Type.DOUBLE, Type.VARCHAR,
                "",
                "",
                "",
                "",
                "",
                false, true, false, true));

        addBuiltin(AggregateFunction.createBuiltin("percentile_approx",
                Lists.<Type>newArrayList(Type.DOUBLE, Type.DOUBLE, Type.DOUBLE), Type.DOUBLE, Type.VARCHAR,
                "",
                "",
                "",
                "",
                "",
                false, true, false, true));

        addBuiltin(AggregateFunction.createBuiltin("percentile_array",
                Lists.newArrayList(Type.BIGINT, new ArrayType(Type.DOUBLE)), new ArrayType(Type.DOUBLE), Type.VARCHAR,
                "", "", "", "", "",
                false, true, false, true));

        // collect_list
        for (Type t : Type.getArraySubTypes()) {
            addBuiltin(AggregateFunction.createBuiltin(COLLECT_LIST, Lists.newArrayList(t), new ArrayType(t), t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(COLLECT_SET, Lists.newArrayList(t), new ArrayType(t), t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(COLLECT_LIST, Lists.newArrayList(t, Type.INT), new ArrayType(t), t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(COLLECT_SET, Lists.newArrayList(t, Type.INT), new ArrayType(t), t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(
                    AggregateFunction.createBuiltin("topn_array", Lists.newArrayList(t, Type.INT), new ArrayType(t), t,
                            "", "", "", "", "", true, false, true, true));
            addBuiltin(
                    AggregateFunction
                            .createBuiltin("topn_array", Lists.newArrayList(t, Type.INT, Type.INT), new ArrayType(t), t,
                                    "", "", "", "", "", true, false, true, true));
            addBuiltin(
                    AggregateFunction
                            .createBuiltin("topn_weighted", Lists.newArrayList(t, Type.BIGINT, Type.INT),
                                    new ArrayType(t),
                                    t,
                                    "", "", "", "", "", true, false, true, true));
            addBuiltin(
                    AggregateFunction
                            .createBuiltin("topn_weighted", Lists.newArrayList(t, Type.BIGINT, Type.INT, Type.INT),
                                    new ArrayType(t), t,
                                    "", "", "", "", "", true, false, true, true));

            // histogram | hist
            addBuiltin(AggregateFunction.createBuiltin(HIST, Lists.newArrayList(t), Type.VARCHAR, t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(HISTOGRAM, Lists.newArrayList(t), Type.VARCHAR, t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(HIST, Lists.newArrayList(t, Type.INT), Type.VARCHAR, t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(HISTOGRAM, Lists.newArrayList(t, Type.INT), Type.VARCHAR, t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(HISTOGRAM, Lists.newArrayList(t, Type.DOUBLE, Type.INT),
                    Type.VARCHAR, t,
                    "", "", "", "", "", true, false, true, true));

            // linear histogram
            addBuiltin(AggregateFunction.createBuiltin(LINEAR_HISTOGRAM,
                    Lists.<Type>newArrayList(t, Type.DOUBLE), Type.VARCHAR, t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(LINEAR_HISTOGRAM,
                    Lists.<Type>newArrayList(t, Type.DOUBLE, Type.DOUBLE), Type.VARCHAR, t,
                    "", "", "", "", "", true, false, true, true));

            // group array
            addBuiltin(AggregateFunction.createBuiltin(GROUP_UNIQ_ARRAY, Lists.newArrayList(t), new ArrayType(t), t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(
                    AggregateFunction.createBuiltin(GROUP_UNIQ_ARRAY, Lists.newArrayList(t, Type.INT), new ArrayType(t),
                            t, "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(GROUP_ARRAY, Lists.newArrayList(t), new ArrayType(t), t,
                    "", "", "", "", "", true, false, true, true));
            addBuiltin(
                    AggregateFunction.createBuiltin(GROUP_ARRAY, Lists.newArrayList(t, Type.INT), new ArrayType(t),
                            t, "", "", "", "", "", true, false, true, true));
            addBuiltin(
                    AggregateFunction.createBuiltin(GROUP_ARRAY_INTERSECT, Lists.newArrayList(new ArrayType(t)),
                            new ArrayType(t), t, "", "", "", "", "", true, false, true, true));
            addBuiltin(AggregateFunction.createBuiltin(ARRAY_AGG, Lists.newArrayList(t), new ArrayType(t), t, "", "", "", "", "",
                    true, false, true, true));

            //first_value/last_value for array
            addBuiltin(AggregateFunction.createAnalyticBuiltin("first_value",
                    Lists.newArrayList(new ArrayType(t)), new ArrayType(t), Type.ARRAY,
                    "",
                    "",
                    null,
                    "",
                    "", true));

            addBuiltin(AggregateFunction.createAnalyticBuiltin("last_value",
                    Lists.newArrayList(new ArrayType(t)), new ArrayType(t), Type.ARRAY,
                    "",
                    "",
                    null,
                    "",
                    "", true));

            addBuiltin(AggregateFunction.createAnalyticBuiltin("first_value",
                    Lists.newArrayList(new ArrayType(t), Type.BOOLEAN), new ArrayType(t), Type.ARRAY,
                    "",
                    "",
                    null,
                    "",
                    "", true));

            addBuiltin(AggregateFunction.createAnalyticBuiltin("last_value",
                    Lists.newArrayList(new ArrayType(t), Type.BOOLEAN), new ArrayType(t), Type.ARRAY,
                    "",
                    "",
                    null,
                    "",
                    "", true));
        }

        // Avg
        // TODO: switch to CHAR(sizeof(AvgIntermediateType) when that becomes available

        // vectorized avg
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.BOOLEAN), Type.DOUBLE, Type.TINYINT,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.TINYINT), Type.DOUBLE, Type.TINYINT,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.SMALLINT), Type.DOUBLE, Type.SMALLINT,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.INT), Type.DOUBLE, Type.INT,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.BIGINT), Type.DOUBLE, Type.BIGINT,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.LARGEINT), Type.DOUBLE, Type.LARGEINT,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.DOUBLE), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.MAX_DECIMALV2_TYPE), Type.MAX_DECIMALV2_TYPE, Type.MAX_DECIMALV2_TYPE,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.DECIMAL32), Type.DECIMAL128, Type.DECIMAL128,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.DECIMAL64), Type.DECIMAL128, Type.DECIMAL128,
                "", "", "", "", "", "", "",
                false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("avg",
                Lists.<Type>newArrayList(Type.DECIMAL128), Type.DECIMAL128, Type.DECIMAL128,
                "", "", "", "", "", "", "",
                false, true, false, true));

        // Group_concat(string) vectorized
        addBuiltin(AggregateFunction.createBuiltin("group_concat", Lists.<Type>newArrayList(Type.VARCHAR), Type.VARCHAR,
                Type.VARCHAR, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("multi_distinct_group_concat", Lists.<Type>newArrayList(Type.VARCHAR), Type.VARCHAR,
                Type.VARCHAR, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("group_concat", Lists.<Type>newArrayList(Type.CHAR), Type.CHAR,
                Type.CHAR, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("multi_distinct_group_concat", Lists.<Type>newArrayList(Type.CHAR), Type.CHAR,
                Type.CHAR, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("group_concat", Lists.<Type>newArrayList(Type.STRING), Type.STRING,
                Type.STRING, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("multi_distinct_group_concat", Lists.<Type>newArrayList(Type.STRING), Type.STRING,
                Type.STRING, "", "", "", "", "", false, true, false, true));
        // Group_concat(string, string) vectorized
        addBuiltin(AggregateFunction.createBuiltin("group_concat", Lists.<Type>newArrayList(Type.VARCHAR, Type.VARCHAR),
                Type.VARCHAR, Type.VARCHAR, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("multi_distinct_group_concat", Lists.<Type>newArrayList(Type.VARCHAR, Type.VARCHAR),
                Type.VARCHAR, Type.VARCHAR, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("group_concat", Lists.<Type>newArrayList(Type.CHAR, Type.CHAR),
                Type.CHAR, Type.CHAR, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("multi_distinct_group_concat", Lists.<Type>newArrayList(Type.CHAR, Type.CHAR),
                Type.CHAR, Type.CHAR, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("group_concat", Lists.<Type>newArrayList(Type.STRING, Type.STRING),
                Type.STRING, Type.STRING, "", "", "", "", "", false, true, false, true));
        addBuiltin(AggregateFunction.createBuiltin("multi_distinct_group_concat", Lists.<Type>newArrayList(Type.STRING, Type.STRING),
                Type.STRING, Type.STRING, "", "", "", "", "", false, true, false, true));

        // analytic functions
        // Rank
        addBuiltin(AggregateFunction.createAnalyticBuiltin("rank",
                Lists.<Type>newArrayList(), Type.BIGINT, Type.VARCHAR,
                "",
                "",
                null,
                "",
                ""));
        // Percent Rank
        addBuiltin(AggregateFunction.createAnalyticBuiltin("percent_rank",
                Lists.<Type>newArrayList(), Type.DOUBLE, Type.VARCHAR,
                "",
                "",
                null,
                "",
                ""));
        // Dense rank
        addBuiltin(AggregateFunction.createAnalyticBuiltin("dense_rank",
                Lists.<Type>newArrayList(), Type.BIGINT, Type.VARCHAR,
                "",
                "",
                null,
                "",
                ""));
        //row_number
        addBuiltin(AggregateFunction.createAnalyticBuiltin("row_number",
                new ArrayList<Type>(), Type.BIGINT, Type.BIGINT,
                "",
                "",
                "",
                null, null));
        //ntile, we use rewrite sql for ntile, actually we don't really need this.
        addBuiltin(AggregateFunction.createAnalyticBuiltin("ntile",
                Collections.singletonList(Type.BIGINT), Type.BIGINT, Type.BIGINT, null, null, null, null, null));

        //vec Rank
        addBuiltin(AggregateFunction.createAnalyticBuiltin("rank",
                Lists.<Type>newArrayList(), Type.BIGINT, Type.VARCHAR,
                "",
                "",
                null,
                "",
                "", true));
        //vec Percent Rank
        addBuiltin(AggregateFunction.createAnalyticBuiltin("percent_rank",
                Lists.<Type>newArrayList(), Type.DOUBLE, Type.VARCHAR,
                "",
                "",
                null,
                "",
                "", true));
        //vec Dense rank
        addBuiltin(AggregateFunction.createAnalyticBuiltin("dense_rank",
                Lists.<Type>newArrayList(), Type.BIGINT, Type.VARCHAR,
                "",
                "",
                null,
                "",
                "", true));
        // vec cume_dist
        addBuiltin(AggregateFunction.createAnalyticBuiltin("cume_dist",
                Lists.<Type>newArrayList(), Type.DOUBLE, Type.VARCHAR,
                "",
                "",
                null,
                "",
                "", true));
        //vec row_number
        addBuiltin(AggregateFunction.createAnalyticBuiltin("row_number",
                new ArrayList<Type>(), Type.BIGINT, Type.BIGINT,
                "",
                "",
                "",
                null, null, true));
        //vec ntile
        addBuiltin(AggregateFunction.createAnalyticBuiltin("ntile",
                Collections.singletonList(Type.BIGINT), Type.BIGINT, Type.BIGINT, null, null, null, null, null, true));

        for (Type t : Type.getTrivialTypes()) {
            if (t.isNull()) {
                continue; // NULL is handled through type promotion.
            }
            if (t.isScalarType(PrimitiveType.CHAR)) {
                continue; // promoted to STRING
            }
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "first_value", Lists.newArrayList(t), t, t,
                    "",
                    "",
                    null,
                    "",
                    ""));

            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "last_value", Lists.newArrayList(t), t, t,
                    "",
                    "",
                    "",
                    "",
                    ""));

            //vec first_value
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "first_value", Lists.newArrayList(t, Type.BOOLEAN), t, t,
                    "",
                    "",
                    null,
                    "",
                    "", true));
            // Implements FIRST_VALUE for some windows that require rewrites during planning.
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "first_value_rewrite", Lists.newArrayList(t, Type.BIGINT), t, t,
                    "",
                    "",
                    null,
                    "",
                    "",
                    false, false));
            //vec last_value
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "last_value", Lists.newArrayList(t, Type.BOOLEAN), t, t,
                    "",
                    "",
                    "",
                    "",
                    "", true));

            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "lag", Lists.newArrayList(t, Type.BIGINT, t), t, t,
                    "",
                    "",
                    null, "", null));

            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "lead", Lists.newArrayList(t, Type.BIGINT, t), t, t,
                    "",
                    "",
                    null, "", null));
            //vec
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "lag", Lists.newArrayList(t, Type.BIGINT, t), t, t,
                    "",
                    "",
                    null, null, null, true));
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "lead", Lists.newArrayList(t, Type.BIGINT, t), t, t,
                    "",
                    "",
                    null, null, null, true));

            // lead() and lag() the default offset and the default value should be
            // rewritten to call the overrides that take all parameters.
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "lag", Lists.newArrayList(t), t, t, false));
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "lag", Lists.newArrayList(t, Type.BIGINT), t, t, false));
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "lead", Lists.newArrayList(t), t, t, false));
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                    "lead", Lists.newArrayList(t, Type.BIGINT), t, t, false));
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                        "lag", Lists.newArrayList(t), t, t, true));
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                        "lag", Lists.newArrayList(t, Type.BIGINT), t, t, true));
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                        "lead", Lists.newArrayList(t), t, t, true));
            addBuiltin(AggregateFunction.createAnalyticBuiltin(
                        "lead", Lists.newArrayList(t, Type.BIGINT), t, t, true));
        }

        // count_by_enum
        addBuiltin(AggregateFunction.createBuiltin(COUNT_BY_ENUM,
                Lists.newArrayList(Type.STRING),
                Type.STRING,
                Type.STRING,
                true,
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                false, true, false, true));

        // corr
        addBuiltin(AggregateFunction.createBuiltin("corr",
                Lists.<Type>newArrayList(Type.TINYINT, Type.TINYINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("corr",
                Lists.<Type>newArrayList(Type.SMALLINT, Type.SMALLINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("corr",
                Lists.<Type>newArrayList(Type.INT, Type.INT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("corr",
                Lists.<Type>newArrayList(Type.BIGINT, Type.BIGINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("corr",
                Lists.<Type>newArrayList(Type.FLOAT, Type.FLOAT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("corr",
                Lists.<Type>newArrayList(Type.DOUBLE, Type.DOUBLE), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));

        // covar
        addBuiltin(AggregateFunction.createBuiltin("covar",
                Lists.<Type>newArrayList(Type.TINYINT, Type.TINYINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar",
                Lists.<Type>newArrayList(Type.SMALLINT, Type.SMALLINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar",
                Lists.<Type>newArrayList(Type.INT, Type.INT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar",
                Lists.<Type>newArrayList(Type.BIGINT, Type.BIGINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar",
                Lists.<Type>newArrayList(Type.FLOAT, Type.FLOAT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar",
                Lists.<Type>newArrayList(Type.DOUBLE, Type.DOUBLE), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));

        addBuiltin(AggregateFunction.createBuiltin("covar_pop",
                Lists.<Type>newArrayList(Type.TINYINT, Type.TINYINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_pop",
                Lists.<Type>newArrayList(Type.SMALLINT, Type.SMALLINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_pop",
                Lists.<Type>newArrayList(Type.INT, Type.INT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_pop",
                Lists.<Type>newArrayList(Type.BIGINT, Type.BIGINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_pop",
                Lists.<Type>newArrayList(Type.FLOAT, Type.FLOAT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_pop",
                Lists.<Type>newArrayList(Type.DOUBLE, Type.DOUBLE), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));

        // covar_samp
        addBuiltin(AggregateFunction.createBuiltin("covar_samp",
                Lists.<Type>newArrayList(Type.TINYINT, Type.TINYINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_samp",
                Lists.<Type>newArrayList(Type.SMALLINT, Type.SMALLINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_samp",
                Lists.<Type>newArrayList(Type.INT, Type.INT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_samp",
                Lists.<Type>newArrayList(Type.BIGINT, Type.BIGINT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_samp",
                Lists.<Type>newArrayList(Type.FLOAT, Type.FLOAT), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));
        addBuiltin(AggregateFunction.createBuiltin("covar_samp",
                Lists.<Type>newArrayList(Type.DOUBLE, Type.DOUBLE), Type.DOUBLE, Type.DOUBLE,
                "", "", "", "", "", "", "",
                false, false, false, true));


        List<String> skewnessAndKurtosis = Lists.newArrayList("skew", "skew_pop", "skewness", "kurt",
                "kurt_pop", "kurtosis");
        skewnessAndKurtosis.addAll(skewnessAndKurtosis);

        for (String name : skewnessAndKurtosis) {
            addBuiltin(AggregateFunction.createBuiltin(name,
                    Lists.<Type>newArrayList(Type.TINYINT), Type.DOUBLE, Type.DOUBLE,
                    "", "", "", "", "", "", "",
                    false, false, false, true));
            addBuiltin(AggregateFunction.createBuiltin(name,
                    Lists.<Type>newArrayList(Type.SMALLINT), Type.DOUBLE, Type.DOUBLE,
                    "", "", "", "", "", "", "",
                    false, false, false, true));
            addBuiltin(AggregateFunction.createBuiltin(name,
                    Lists.<Type>newArrayList(Type.INT), Type.DOUBLE, Type.DOUBLE,
                    "", "", "", "", "", "", "",
                    false, false, false, true));
            addBuiltin(AggregateFunction.createBuiltin(name,
                    Lists.<Type>newArrayList(Type.BIGINT), Type.DOUBLE, Type.DOUBLE,
                    "", "", "", "", "", "", "",
                    false, false, false, true));
            addBuiltin(AggregateFunction.createBuiltin(name,
                    Lists.<Type>newArrayList(Type.LARGEINT), Type.DOUBLE, Type.DOUBLE,
                    "", "", "", "", "", "", "",
                    false, false, false, true));
            addBuiltin(AggregateFunction.createBuiltin(name,
                    Lists.<Type>newArrayList(Type.FLOAT), Type.DOUBLE, Type.DOUBLE,
                    "", "", "", "", "", "", "",
                    false, false, false, true));
            addBuiltin(AggregateFunction.createBuiltin(name,
                    Lists.<Type>newArrayList(Type.DOUBLE), Type.DOUBLE, Type.DOUBLE,
                    "", "", "", "", "", "", "",
                    false, false, false, true));
        }
    }

    public Map<String, List<Function>> getVectorizedFunctions() {
        return ImmutableMap.copyOf(vectorizedFunctions);
    }

    public List<Function> getBulitinFunctions() {
        List<Function> builtinFunctions = Lists.newArrayList();
        for (Map.Entry<String, List<Function>> entry : vectorizedFunctions.entrySet()) {
            builtinFunctions.addAll(entry.getValue());
        }
        return builtinFunctions;
    }

    public List<Function> getAllFunctions() {
        List<Function> functions = Lists.newArrayList();
        vectorizedFunctions.forEach((k, v) -> functions.addAll(v));
        tableFunctions.forEach((k, v) -> functions.addAll(v));
        return functions;
    }

    public static final String EXPLODE_SPLIT = "explode_split";
    public static final String EXPLODE_BITMAP = "explode_bitmap";
    public static final String EXPLODE_JSON_ARRAY_INT = "explode_json_array_int";
    public static final String EXPLODE_JSON_ARRAY_DOUBLE = "explode_json_array_double";
    public static final String EXPLODE_JSON_ARRAY_STRING = "explode_json_array_string";
    public static final String EXPLODE_JSON_ARRAY_JSON = "explode_json_array_json";
    public static final String EXPLODE_NUMBERS = "explode_numbers";
    public static final String EXPLODE = "explode";

    private void addTableFunction(String name, Type retType, NullableMode nullableMode, ArrayList<Type> argTypes,
            boolean hasVarArgs, String symbol) {
        List<Function> functionList = tableFunctions.get(name);
        functionList.add(ScalarFunction.createBuiltin(name, retType, nullableMode, argTypes, hasVarArgs, symbol, null,
                null, true));
    }

    private void addTableFunctionWithCombinator(String name, Type retType, NullableMode nullableMode,
            ArrayList<Type> argTypes, boolean hasVarArgs, String symbol) {
        addTableFunction(name, retType, nullableMode, argTypes, hasVarArgs, symbol);
        addTableFunction(name + "_outer", retType, Function.NullableMode.ALWAYS_NULLABLE, argTypes, hasVarArgs, symbol);
    }

    private void initTableFunctionListWithCombinator(String name) {
        tableFunctions.put(name, Lists.newArrayList());
        tableFunctions.put(name + "_outer", Lists.newArrayList());
    }

    private void initTableFunction() {
        initTableFunctionListWithCombinator(EXPLODE_SPLIT);
        addTableFunctionWithCombinator(EXPLODE_SPLIT, Type.VARCHAR, Function.NullableMode.DEPEND_ON_ARGUMENT,
                Lists.newArrayList(Type.VARCHAR, Type.VARCHAR), false,
                "_ZN5doris19DummyTableFunctions13explode_splitEPN9doris_udf15FunctionContextERKNS1_9StringValES6_");

        initTableFunctionListWithCombinator(EXPLODE_BITMAP);
        addTableFunctionWithCombinator(EXPLODE_BITMAP, Type.BIGINT, Function.NullableMode.DEPEND_ON_ARGUMENT,
                Lists.newArrayList(Type.BITMAP), false,
                "_ZN5doris19DummyTableFunctions14explode_bitmapEPN9doris_udf15FunctionContextERKNS1_9StringValE");

        initTableFunctionListWithCombinator(EXPLODE_JSON_ARRAY_INT);
        addTableFunctionWithCombinator(EXPLODE_JSON_ARRAY_INT, Type.BIGINT, Function.NullableMode.DEPEND_ON_ARGUMENT,
                Lists.newArrayList(Type.VARCHAR), false,
                "_ZN5doris19DummyTableFunctions22explode_json_array_intEPN9doris_udf15FunctionContextERKNS1_9StringValE");

        initTableFunctionListWithCombinator(EXPLODE_JSON_ARRAY_DOUBLE);
        addTableFunctionWithCombinator(EXPLODE_JSON_ARRAY_DOUBLE, Type.DOUBLE, Function.NullableMode.DEPEND_ON_ARGUMENT,
                Lists.newArrayList(Type.VARCHAR), false,
                "_ZN5doris19DummyTableFunctions25explode_json_array_doubleEPN9doris_udf15FunctionContextERKNS1_9StringValE");

        initTableFunctionListWithCombinator(EXPLODE_JSON_ARRAY_STRING);
        addTableFunctionWithCombinator(EXPLODE_JSON_ARRAY_STRING, Type.VARCHAR,
                Function.NullableMode.DEPEND_ON_ARGUMENT, Lists.newArrayList(Type.VARCHAR), false,
                "_ZN5doris19DummyTableFunctions25explode_json_array_stringEPN9doris_udf15FunctionContextERKNS1_9StringValE");

        initTableFunctionListWithCombinator(EXPLODE_JSON_ARRAY_JSON);
        addTableFunctionWithCombinator(EXPLODE_JSON_ARRAY_JSON, Type.VARCHAR,
                Function.NullableMode.DEPEND_ON_ARGUMENT, Lists.newArrayList(Type.VARCHAR), false,
                "_ZN5doris19DummyTableFunctions25explode_json_array_jsonEPN9doris_udf15FunctionContextERKNS1_9StringValE");

        initTableFunctionListWithCombinator(EXPLODE_NUMBERS);
        addTableFunctionWithCombinator(EXPLODE_NUMBERS, Type.INT, Function.NullableMode.DEPEND_ON_ARGUMENT,
                Lists.newArrayList(Type.INT), false,
                "_ZN5doris19DummyTableFunctions22explode_numbersEPN9doris_udf15FunctionContextERKNS1_9IntValE");

        initTableFunctionListWithCombinator(EXPLODE);
        for (Type subType : Type.getArraySubTypes()) {
            addTableFunctionWithCombinator(EXPLODE, subType, Function.NullableMode.ALWAYS_NULLABLE,
                    Lists.newArrayList(new ArrayType(subType)), false,
                    "_ZN5doris19DummyTableFunctions7explodeEPN9doris_udf15FunctionContextERKNS1_13CollectionValE");
        }
        addTableFunctionWithCombinator(EXPLODE, Type.WILDCARD_DECIMAL, Function.NullableMode.ALWAYS_NULLABLE,
                Lists.newArrayList(new ArrayType(Type.WILDCARD_DECIMAL)), false,
                "_ZN5doris19DummyTableFunctions7explodeEPN9doris_udf15FunctionContextERKNS1_13CollectionValE");

    }

    public boolean isAggFunctionName(String name) {
        return aggFunctionNames.contains(name);
    }
}