diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionRegistry.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionRegistry.java index bb26f2bef5..3a08fce575 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionRegistry.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionRegistry.java @@ -33,6 +33,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import java.util.List; import java.util.Map; @@ -86,24 +87,31 @@ public class FunctionRegistry { // currently we only find function by name and arity and args' types. public FunctionBuilder findFunctionBuilder(String dbName, String name, List arguments) { + List functionBuilders = null; int arity = arguments.size(); - List functionBuilders = name2InternalBuiltinBuilders.get(name.toLowerCase()); - if (CollectionUtils.isEmpty(functionBuilders) && AggStateFunctionBuilder.isAggStateCombinator(name)) { - String nestedName = AggStateFunctionBuilder.getNestedName(name); - String combinatorSuffix = AggStateFunctionBuilder.getCombinatorSuffix(name); + String qualifiedName = StringUtils.isEmpty(dbName) ? name : dbName + "." + name; - functionBuilders = name2InternalBuiltinBuilders.get(nestedName.toLowerCase()); - - if (functionBuilders != null) { - functionBuilders = functionBuilders.stream().map(builder -> { - return new AggStateFunctionBuilder(combinatorSuffix, builder); - }).filter(functionBuilder -> functionBuilder.canApply(arguments)).collect(Collectors.toList()); + if (StringUtils.isEmpty(dbName)) { + // search internal function only if dbName is empty + functionBuilders = name2InternalBuiltinBuilders.get(name.toLowerCase()); + if (CollectionUtils.isEmpty(functionBuilders) && AggStateFunctionBuilder.isAggStateCombinator(name)) { + String nestedName = AggStateFunctionBuilder.getNestedName(name); + String combinatorSuffix = AggStateFunctionBuilder.getCombinatorSuffix(name); + functionBuilders = name2InternalBuiltinBuilders.get(nestedName.toLowerCase()); + if (functionBuilders != null) { + functionBuilders = functionBuilders.stream() + .map(builder -> new AggStateFunctionBuilder(combinatorSuffix, builder)) + .filter(functionBuilder -> functionBuilder.canApply(arguments)) + .collect(Collectors.toList()); + } } } - if (functionBuilders == null || functionBuilders.isEmpty()) { + + // search udf + if (CollectionUtils.isEmpty(functionBuilders)) { functionBuilders = findUdfBuilder(dbName, name); if (functionBuilders == null || functionBuilders.isEmpty()) { - throw new AnalysisException("Can not found function '" + name + "'"); + throw new AnalysisException("Can not found function '" + qualifiedName + "'"); } } @@ -113,15 +121,15 @@ public class FunctionRegistry { .collect(Collectors.toList()); if (candidateBuilders.isEmpty()) { String candidateHints = getCandidateHint(name, functionBuilders); - throw new AnalysisException("Can not found function '" + name + throw new AnalysisException("Can not found function '" + qualifiedName + "' which has " + arity + " arity. Candidate functions are: " + candidateHints); } - if (candidateBuilders.size() > 1) { String candidateHints = getCandidateHint(name, candidateBuilders); // NereidsPlanner not supported override function by the same arity, should we support it? - throw new AnalysisException("Function '" + name + "' is ambiguous: " + candidateHints); + throw new AnalysisException("Function '" + qualifiedName + "' is ambiguous: " + candidateHints); } + return candidateBuilders.get(0); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FunctionBinder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FunctionBinder.java index 4f5def6f1e..ac6a83f9cf 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FunctionBinder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FunctionBinder.java @@ -59,6 +59,7 @@ import org.apache.doris.nereids.types.DataType; import org.apache.doris.nereids.util.TypeCoercionUtils; import com.google.common.collect.ImmutableList; +import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; @@ -142,7 +143,6 @@ public class FunctionBinder extends AbstractExpressionRewriteRule { // bind function FunctionRegistry functionRegistry = Env.getCurrentEnv().getFunctionRegistry(); - String functionName = unboundFunction.getName(); List arguments = unboundFunction.isDistinct() ? ImmutableList.builder() .add(unboundFunction.isDistinct()) @@ -150,14 +150,17 @@ public class FunctionBinder extends AbstractExpressionRewriteRule { .build() : (List) unboundFunction.getArguments(); - // we will change arithmetic function like add(), subtract(), bitnot() to the corresponding objects rather than - // BoundFunction. - ArithmeticFunctionBinder functionBinder = new ArithmeticFunctionBinder(); - if (functionBinder.isBinaryArithmetic(unboundFunction.getName())) { - return functionBinder.bindBinaryArithmetic(unboundFunction.getName(), unboundFunction.children()) - .accept(this, context); + if (StringUtils.isEmpty(unboundFunction.getDbName())) { + // we will change arithmetic function like add(), subtract(), bitnot() + // to the corresponding objects rather than BoundFunction. + ArithmeticFunctionBinder functionBinder = new ArithmeticFunctionBinder(); + if (functionBinder.isBinaryArithmetic(unboundFunction.getName())) { + return functionBinder.bindBinaryArithmetic(unboundFunction.getName(), unboundFunction.children()) + .accept(this, context); + } } + String functionName = unboundFunction.getName(); FunctionBuilder builder = functionRegistry.findFunctionBuilder( unboundFunction.getDbName(), functionName, arguments); if (builder instanceof AliasUdfBuilder) { diff --git a/regression-test/suites/nereids_syntax_p0/function.groovy b/regression-test/suites/nereids_syntax_p0/function.groovy index 3fbb8e55cb..41e6309aab 100644 --- a/regression-test/suites/nereids_syntax_p0/function.groovy +++ b/regression-test/suites/nereids_syntax_p0/function.groovy @@ -189,5 +189,10 @@ suite("nereids_function") { qt_regexp_extract_all """ SELECT regexp_extract_all('AbCdE', '([[:lower:]]+)C([[:lower:]]+)') """ + + test { + sql "select `hello`.now(3)" + exception "Can not found function" + } }