在 Doris 中自定义 UDF 时,若函数名与内置函数重名,调用时必须加上数据库名才能正确执行。如果不希望每次调用都携带数据库名,该如何解决?

Viewed 21

基础信息

版本:doris4.0.2

问题描述

在 Doris 数据库中注册自定义 UDF 时,如果函数名与内置函数重名(例如 date_add),直接调用会因名称冲突而报错,必须使用库名限定(如 db_name.date_add)才能正常执行。如下图所示:

不带库名调用

image.png

带有库名调用

image.png

通过官网的AI,给出的解决方式是添加,问题还是没有得到解决。如下图所示:

SET prefer_udf_over_builtin = true;

image.png

自定义UDF代码

package com.travelsky.udf.cross.presto;

import org.apache.hadoop.hive.ql.exec.UDF;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.Temporal;

/**
 * 自定义日期函数,用于解决doris原本的 date_add 与presto参数不一致问题
 */
public class DateAdd extends UDF {

    /**
     * 实现 Presto 的 date_add 功能
     *
     * @param unit   时间单位 ("day", "month", "year")
     * @param amount 要添加的数量
     * @param date   输入的日期字符串 (格式: yyyy-MM-dd)
     * @return 添加后的新日期字符串 (格式: yyyy-mm-dd)
     */
    public <T extends Temporal> LocalDate evaluate(String unit, int amount, LocalDate date) {
        return dateAdd(unit, amount, date);
    }

    /**
     * 实现 Presto 的 date_add 功能
     *
     * @param unit   时间单位 ("day", "month", "year")
     * @param amount 要添加的数量
     * @param date   输入的日期字符串 (格式: yyyy-MM-dd HH:mm:ss)
     * @return 添加后的新日期字符串 (格式: yyyy-MM-dd HH:mm:ss)
     */
    public <T extends Temporal> LocalDateTime evaluate(String unit, int amount, LocalDateTime date) {
        return dateAdd(unit, amount, date);
    }

    /**
     * 实现 Presto 的 date_add 功能
     *
     * @param unit   时间单位 ("day", "month", "year")
     * @param amount 要添加的数量
     * @param date   输入的日期对象 (LocalDate 或 LocalDateTime)
     * @return 添加后的新日期对象 (与输入类型一致)
     */
    public <T extends Temporal> T dateAdd(String unit, int amount, T date) {

        if (date == null) {
            throw new IllegalArgumentException("Date cannot be null");
        }
        LocalDateTime dateTime;
        // 判断输入类型并转换为 LocalDateTime
        if (date instanceof LocalDate) {
            dateTime = ((LocalDate) date).atStartOfDay();
        } else if (date instanceof LocalDateTime) {
            dateTime = (LocalDateTime) date;
        } else {
            throw new IllegalArgumentException("Unsupported Temporal type: " + date.getClass().getSimpleName());
        }

        // 根据时间单位进行日期计算
        switch (unit.toLowerCase()) {
            case "second":
                dateTime = dateTime.plusSeconds(amount);
                break;
            case "minute":
                dateTime = dateTime.plusMinutes(amount);
                break;
            case "hour":
                dateTime = dateTime.plusHours(amount);
                break;
            case "day":
                dateTime = dateTime.plusDays(amount);
                break;
            case "week":
                dateTime = dateTime.plusWeeks(amount);
                break;
            case "month":
                dateTime = dateTime.plusMonths(amount);
                break;
            case "quarter":
                dateTime = dateTime.plusMonths(amount * 3L);
                break;
            case "year":
                dateTime = dateTime.plusYears(amount);
                break;
            default:
                throw new IllegalArgumentException("Unsupported time unit: " + unit);
        }
        // 根据原始输入类型返回对应类型的对象
        if (date instanceof LocalDate) {
            return (T) dateTime.toLocalDate();
        } else {
            return (T) dateTime;
        }
    }

}

1 Answers

https://github.com/apache/doris/pull/60674

Doris 会对一些内置函数做特殊处理,date_add 正好是其中一个。上面的PR优化了这里的逻辑,可以先打patch试试。
其他函数,使用 set prefer_udf_over_builtin=true; 是可以的