This is an automated email from the ASF dual-hosted git repository. xxyu pushed a commit to branch kylin5 in repository https://gitbox.apache.org/repos/asf/kylin.git
commit f929bd876ed54afbd1490d2717894288fd197ec6 Author: sibingzhang <74443791+sibingzh...@users.noreply.github.com> AuthorDate: Tue Feb 14 13:54:41 2023 +0800 KYLIN-5524 Supports CONCAT for variable arguments --- .../kylin/query/udf/stringUdf/ConcatUDF.java | 45 +++++++++++++++++++--- .../org/apache/kylin/query/udf/StringUDFTest.java | 21 +++++++--- .../kylin/query/runtime/ExpressionConverter.scala | 2 +- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/query/src/main/java/org/apache/kylin/query/udf/stringUdf/ConcatUDF.java b/src/query/src/main/java/org/apache/kylin/query/udf/stringUdf/ConcatUDF.java index 01f16d47e6..841cc16bfe 100644 --- a/src/query/src/main/java/org/apache/kylin/query/udf/stringUdf/ConcatUDF.java +++ b/src/query/src/main/java/org/apache/kylin/query/udf/stringUdf/ConcatUDF.java @@ -18,14 +18,49 @@ package org.apache.kylin.query.udf.stringUdf; -import org.apache.calcite.linq4j.function.Parameter; +import org.apache.calcite.adapter.enumerable.CallImplementor; +import org.apache.calcite.adapter.enumerable.UdfMethodNameImplementor; +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.sql.SqlFunction; +import org.apache.calcite.sql.SqlFunctionCategory; +import org.apache.calcite.sql.SqlIdentifier; +import org.apache.calcite.sql.fun.udf.UdfDef; +import org.apache.calcite.sql.parser.SqlParserPos; +import org.apache.calcite.sql.type.OperandTypes; +import org.apache.calcite.sql.type.ReturnTypes; +import org.apache.calcite.sql.type.SqlOperandCountRanges; +import org.apache.calcite.sql.type.SqlTypeName; +import org.apache.calcite.sql.type.SqlTypeTransforms; -public class ConcatUDF { +import java.util.Arrays; +import java.util.stream.Collectors; - public String CONCAT(@Parameter(name = "col1") Object col1, @Parameter(name = "col2") Object col2) { - if (col1 == null || col2 == null) { +public class ConcatUDF implements UdfDef { + + private static final String FUNC_NAME = "CONCAT"; + + private ConcatUDF() { + throw new IllegalStateException("Utility class"); + } + + public static final SqlFunction OPERATOR = new SqlFunction(new SqlIdentifier(FUNC_NAME, SqlParserPos.ZERO), + ReturnTypes.cascade(opBinding -> { + int precision = opBinding.collectOperandTypes().stream().mapToInt(RelDataType::getPrecision).sum(); + return opBinding.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, precision); + }, SqlTypeTransforms.TO_NULLABLE), + (callBinding, returnType, operandTypes) -> Arrays.fill(operandTypes, + callBinding.getTypeFactory().createJavaType(Object.class)), + OperandTypes.repeat(SqlOperandCountRanges.from(2), OperandTypes.ANY), null, + SqlFunctionCategory.USER_DEFINED_FUNCTION); + + public static final CallImplementor IMPLEMENTOR = new UdfMethodNameImplementor(FUNC_NAME.toLowerCase(), + ConcatUDF.class); + + public static String concat(Object... args) { + if (args == null) { return null; } - return "" + col1 + col2; + + return Arrays.stream(args).map(String::valueOf).collect(Collectors.joining()); } } diff --git a/src/query/src/test/java/org/apache/kylin/query/udf/StringUDFTest.java b/src/query/src/test/java/org/apache/kylin/query/udf/StringUDFTest.java index 543795a2aa..799660a37f 100644 --- a/src/query/src/test/java/org/apache/kylin/query/udf/StringUDFTest.java +++ b/src/query/src/test/java/org/apache/kylin/query/udf/StringUDFTest.java @@ -33,16 +33,27 @@ import org.junit.Test; public class StringUDFTest { @Test - public void testConcatUDF() throws Exception { - ConcatUDF cu = new ConcatUDF(); - String str1 = cu.CONCAT("Apache ", "Kylin"); + public void testConcatUDF() { + String str1 = ConcatUDF.concat("Apache ", "Kylin"); assertEquals("Apache Kylin", str1); - String str2 = cu.CONCAT("", "Kylin"); + String str2 = ConcatUDF.concat("", "Kylin"); assertEquals("Kylin", str2); - String str3 = cu.CONCAT("Apache", ""); + String str3 = ConcatUDF.concat("Apache", ""); assertEquals("Apache", str3); + + String str4 = ConcatUDF.concat("Apache", 1); + assertEquals("Apache1", str4); + + String str5 = ConcatUDF.concat(1, 1); + assertEquals("11", str5); + + String str6 = ConcatUDF.concat("Apache ", "Kylin", " Kyligence"); + assertEquals("Apache Kylin Kyligence", str6); + + String str7 = ConcatUDF.concat(null); + assertNull(str7); } @Test diff --git a/src/spark-project/sparder/src/main/scala/org/apache/kylin/query/runtime/ExpressionConverter.scala b/src/spark-project/sparder/src/main/scala/org/apache/kylin/query/runtime/ExpressionConverter.scala index a839116059..856c19f50f 100644 --- a/src/spark-project/sparder/src/main/scala/org/apache/kylin/query/runtime/ExpressionConverter.scala +++ b/src/spark-project/sparder/src/main/scala/org/apache/kylin/query/runtime/ExpressionConverter.scala @@ -284,7 +284,7 @@ object ExpressionConverter { else children.apply(2).asInstanceOf[Int] new Column(StringLocate(k_lit(children.head).expr, k_lit(children.apply(1)).expr, lit(pos).expr)) //position(substr,str,start) case "concat" => - concat(k_lit(children.head), k_lit(children.apply(1))) + concat(children.map(k_lit): _*) case "concat_ws" => concat_ws(children.head.toString, k_lit(children.apply(1))) case "split_part" =>