diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index e6fc906f47841c..cb84945ce76de7 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -247,12 +247,12 @@ supportedCreateStatement | CREATE ENCRYPTKEY (IF NOT EXISTS)? multipartIdentifier AS STRING_LITERAL #createEncryptkey | CREATE statementScope? (TABLES | AGGREGATE)? FUNCTION (IF NOT EXISTS)? - functionIdentifier LEFT_PAREN functionArguments? RIGHT_PAREN + functionIdentifier LEFT_PAREN dataTypeList? RIGHT_PAREN RETURNS returnType=dataType (INTERMEDIATE intermediateType=dataType)? properties=propertyClause? (AS functionCode=dollarQuotedString)? #createUserDefineFunction | CREATE statementScope? ALIAS FUNCTION (IF NOT EXISTS)? - functionIdentifier LEFT_PAREN functionArguments? RIGHT_PAREN + functionIdentifier LEFT_PAREN dataTypeList? RIGHT_PAREN WITH PARAMETER LEFT_PAREN parameters=identifierSeq? RIGHT_PAREN AS expression #createAliasFunction | CREATE USER (IF NOT EXISTS)? grantUserIdentify diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index 2fc12d07288f3f..4659bf3b69efaa 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -5667,12 +5667,9 @@ public Command visitCreateUserDefineFunction(CreateUserDefineFunctionContext ctx boolean isAggFunction = ctx.AGGREGATE() != null; boolean isTableFunction = ctx.TABLES() != null; FunctionName function = visitFunctionIdentifier(ctx.functionIdentifier()); - FunctionArgTypesInfo functionArgTypesInfo; - if (ctx.functionArguments() != null) { - functionArgTypesInfo = visitFunctionArguments(ctx.functionArguments()); - } else { - functionArgTypesInfo = new FunctionArgTypesInfo(new ArrayList<>(), false); - } + List argTypes = ctx.dataTypeList() == null + ? new ArrayList<>() : visitDataTypeList(ctx.dataTypeList()); + FunctionArgTypesInfo functionArgTypesInfo = new FunctionArgTypesInfo(argTypes, false); DataType returnType = typedVisit(ctx.returnType); returnType = returnType.conversion(); DataType intermediateType = ctx.intermediateType != null ? typedVisit(ctx.intermediateType) : null; @@ -5693,12 +5690,9 @@ public Command visitCreateAliasFunction(CreateAliasFunctionContext ctx) { SetType statementScope = visitStatementScope(ctx.statementScope()); boolean ifNotExists = ctx.EXISTS() != null; FunctionName function = visitFunctionIdentifier(ctx.functionIdentifier()); - FunctionArgTypesInfo functionArgTypesInfo; - if (ctx.functionArguments() != null) { - functionArgTypesInfo = visitFunctionArguments(ctx.functionArguments()); - } else { - functionArgTypesInfo = new FunctionArgTypesInfo(new ArrayList<>(), false); - } + List argTypes = ctx.dataTypeList() == null + ? new ArrayList<>() : visitDataTypeList(ctx.dataTypeList()); + FunctionArgTypesInfo functionArgTypesInfo = new FunctionArgTypesInfo(argTypes, false); List parameters = ctx.parameters != null ? visitIdentifierSeq(ctx.parameters) : new ArrayList<>(); Expression originFunction = getExpression(ctx.expression()); return new CreateFunctionCommand(statementScope, ifNotExists, false, true, false, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdafBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdafBuilder.java index 4822ab6ef1a012..6abb1f2787630b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdafBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdafBuilder.java @@ -63,7 +63,7 @@ public Class functionClass() { @Override public boolean canApply(List arguments) { - if ((isVarArgs && arity > arguments.size() + 1) || (!isVarArgs && arguments.size() != arity)) { + if (arguments.size() != arity) { return false; } for (Object argument : arguments) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdfBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdfBuilder.java index 6ab90cb42cddac..27d5c62da6db45 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdfBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdfBuilder.java @@ -65,7 +65,7 @@ public Class functionClass() { @Override public boolean canApply(List arguments) { - if ((isVarArgs && arity > arguments.size() + 1) || (!isVarArgs && arguments.size() != arity)) { + if (arguments.size() != arity) { return false; } for (Object argument : arguments) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdtfBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdtfBuilder.java index f00fa22cf5bb82..201d583351d76b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdtfBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/JavaUdtfBuilder.java @@ -65,7 +65,7 @@ public Class functionClass() { @Override public boolean canApply(List arguments) { - if ((isVarArgs && arity > arguments.size() + 1) || (!isVarArgs && arguments.size() != arity)) { + if (arguments.size() != arity) { return false; } for (Object argument : arguments) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdafBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdafBuilder.java index d18800fd429f87..de8a69c7c4899d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdafBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdafBuilder.java @@ -63,7 +63,7 @@ public Class functionClass() { @Override public boolean canApply(List arguments) { - if ((isVarArgs && arity > arguments.size() + 1) || (!isVarArgs && arguments.size() != arity)) { + if (arguments.size() != arity) { return false; } for (Object argument : arguments) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdfBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdfBuilder.java index 85ff1035c3d574..af9f4586296738 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdfBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdfBuilder.java @@ -65,7 +65,7 @@ public Class functionClass() { @Override public boolean canApply(List arguments) { - if ((isVarArgs && arity > arguments.size() + 1) || (!isVarArgs && arguments.size() != arity)) { + if (arguments.size() != arity) { return false; } for (Object argument : arguments) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdtfBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdtfBuilder.java index dd9638f3c205fe..e28e05fd827e9d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdtfBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/udf/PythonUdtfBuilder.java @@ -65,7 +65,7 @@ public Class functionClass() { @Override public boolean canApply(List arguments) { - if ((isVarArgs && arity > arguments.size() + 1) || (!isVarArgs && arguments.size() != arity)) { + if (arguments.size() != arity) { return false; } for (Object argument : arguments) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateFunctionCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateFunctionCommand.java index bc817d50fd3eb8..0fcd335c1cb285 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateFunctionCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateFunctionCommand.java @@ -529,7 +529,7 @@ private void analyzeUdtf() throws AnalysisException { } function = ScalarFunction.createUdf(binaryType, functionName, argsDef.getArgTypes(), - ((ArrayType) (returnType.toCatalogDataType())).getItemType(), argsDef.isVariadic(), + ((ArrayType) (returnType.toCatalogDataType())).getItemType(), false, location, symbol, null, null); function.setChecksum(checksum); function.setNullableMode(returnNullMode); @@ -551,7 +551,7 @@ private void analyzeUdaf() throws AnalysisException { location = null; } builder.name(functionName).argsType(argsDef.getArgTypes()).retType(returnType.toCatalogDataType()) - .hasVarArgs(argsDef.isVariadic()).intermediateType(intermediateType.toCatalogDataType()) + .hasVarArgs(false).intermediateType(intermediateType.toCatalogDataType()) .location(location); String initFnSymbol = properties.get(INIT_KEY); if (initFnSymbol == null && !(binaryType == TFunctionBinaryType.JAVA_UDF @@ -641,7 +641,7 @@ private void analyzeUdf() throws AnalysisException { } function = ScalarFunction.createUdf(binaryType, functionName, argsDef.getArgTypes(), - returnType.toCatalogDataType(), argsDef.isVariadic(), + returnType.toCatalogDataType(), false, location, symbol, prepareFnSymbol, closeFnSymbol); function.setChecksum(checksum); function.setNullableMode(returnNullMode); @@ -1174,7 +1174,7 @@ private void analyzeAliasFunction(ConnectContext ctx) throws AnalysisException { } Map sessionVariables = ConnectContextUtil.getAffectQueryResultInPlanVariables(ctx); function = AliasFunction.createFunction(functionName, argsDef.getArgTypes(), - Type.VARCHAR, argsDef.isVariadic(), parameters, translateToLegacyExpr(originFunction, ctx), + Type.VARCHAR, false, parameters, translateToLegacyExpr(originFunction, ctx), sessionVariables); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java index 8dd5fbe0f49f3a..9fb470b46ca129 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java @@ -882,14 +882,23 @@ public void testCreateCatalog() { @Test public void testCreateFunction() { NereidsParser nereidsParser = new NereidsParser(); - String sql = "create session tables function func_a (int, ...) returns boolean properties('k'='v')"; - nereidsParser.parseSingle(sql); + nereidsParser.parseSingle( + "create session tables function func_a(int) returns boolean properties('k'='v')"); + nereidsParser.parseSingle("create local aggregate function func_a(int) returns boolean " + + "intermediate varchar properties('k'='v')"); + nereidsParser.parseSingle("create alias function func_a(int) with parameter(id) as abs(id)"); - sql = "create local aggregate function func_a (int, ...) returns boolean intermediate varchar properties('k'='v')"; - nereidsParser.parseSingle(sql); + Assertions.assertThrows(ParseException.class, () -> nereidsParser.parseSingle( + "create function func_a(int, ...) returns boolean properties('k'='v')")); + Assertions.assertThrows(ParseException.class, () -> nereidsParser.parseSingle( + "create aggregate function func_a(int, ...) returns boolean properties('k'='v')")); + Assertions.assertThrows(ParseException.class, () -> nereidsParser.parseSingle( + "create tables function func_a(int, ...) returns boolean properties('k'='v')")); + Assertions.assertThrows(ParseException.class, () -> nereidsParser.parseSingle( + "create alias function func_a(int, ...) with parameter(id) as abs(id)")); - sql = "create alias function func_a (int) with parameter(id) as abs(id)"; - nereidsParser.parseSingle(sql); + nereidsParser.parseSingle("drop function func_a(int, ...)"); + nereidsParser.parseSingle("show create function func_a(int, ...)"); } @Test diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/udf/UdfBuilderArityTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/udf/UdfBuilderArityTest.java new file mode 100644 index 00000000000000..fc7e3dd76c2e07 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/udf/UdfBuilderArityTest.java @@ -0,0 +1,68 @@ +// 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.nereids.trees.expressions.functions.udf; + +import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral; + +import com.google.common.collect.ImmutableList; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class UdfBuilderArityTest { + + @Test + void testVariadicMetadataDoesNotEnableVariableArity() { + JavaUdf javaUdf = Mockito.mock(JavaUdf.class); + Mockito.when(javaUdf.hasVarArguments()).thenReturn(true); + Mockito.when(javaUdf.arity()).thenReturn(2); + assertFixedArity(new JavaUdfBuilder(javaUdf)); + + JavaUdaf javaUdaf = Mockito.mock(JavaUdaf.class); + Mockito.when(javaUdaf.hasVarArguments()).thenReturn(true); + Mockito.when(javaUdaf.arity()).thenReturn(2); + assertFixedArity(new JavaUdafBuilder(javaUdaf)); + + JavaUdtf javaUdtf = Mockito.mock(JavaUdtf.class); + Mockito.when(javaUdtf.hasVarArguments()).thenReturn(true); + Mockito.when(javaUdtf.arity()).thenReturn(2); + assertFixedArity(new JavaUdtfBuilder(javaUdtf)); + + PythonUdf pythonUdf = Mockito.mock(PythonUdf.class); + Mockito.when(pythonUdf.hasVarArguments()).thenReturn(true); + Mockito.when(pythonUdf.arity()).thenReturn(2); + assertFixedArity(new PythonUdfBuilder(pythonUdf)); + + PythonUdaf pythonUdaf = Mockito.mock(PythonUdaf.class); + Mockito.when(pythonUdaf.hasVarArguments()).thenReturn(true); + Mockito.when(pythonUdaf.arity()).thenReturn(2); + assertFixedArity(new PythonUdafBuilder(pythonUdaf)); + + PythonUdtf pythonUdtf = Mockito.mock(PythonUdtf.class); + Mockito.when(pythonUdtf.hasVarArguments()).thenReturn(true); + Mockito.when(pythonUdtf.arity()).thenReturn(2); + assertFixedArity(new PythonUdtfBuilder(pythonUdtf)); + } + + private void assertFixedArity(UdfBuilder builder) { + Assertions.assertFalse(builder.canApply(ImmutableList.of(new IntegerLiteral(1)))); + Assertions.assertTrue(builder.canApply(ImmutableList.of(new IntegerLiteral(1), new IntegerLiteral(2)))); + Assertions.assertFalse(builder.canApply( + ImmutableList.of(new IntegerLiteral(1), new IntegerLiteral(2), new IntegerLiteral(3)))); + } +}