From 2f37e108e3a91f65745676c4bc010d5ba5dbb241 Mon Sep 17 00:00:00 2001 From: camby <104178625@qq.com> Date: Mon, 20 Jun 2022 09:35:06 +0800 Subject: [PATCH] [feature-wip](array-type) add ArrayType support for FeFunctions (#10041) FEFunctionSignature do not support ArrayType as args, then following SQL failed: `> select array_contains([1,2,3], 1);` ERROR 1105 (HY000): errCode = 2, detailMessage = Unexpected exception: org.apache.doris.catalog.ArrayType cannot be cast to org.apache.doris.catalog.ScalarType --- .../doris/analysis/ExpressionFunctions.java | 22 ++-- .../org/apache/doris/catalog/ArrayType.java | 2 +- .../org/apache/doris/rewrite/FEFunctions.java | 13 ++- .../test_array_functions_by_literal.out | 100 ++++++++++++++++++ .../test_array_functions_by_literal.groovy | 62 +++++++++++ 5 files changed, 184 insertions(+), 15 deletions(-) create mode 100644 regression-test/data/query/sql_functions/array_functions/test_array_functions_by_literal.out create mode 100644 regression-test/suites/query/sql_functions/array_functions/test_array_functions_by_literal.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java index 035cd8a67b..4325f1168b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java @@ -93,12 +93,8 @@ public enum ExpressionFunctions { return constExpr; } - List argTypes = new ArrayList<>(); - for (Type type : fn.getArgs()) { - argTypes.add((ScalarType) type); - } FEFunctionSignature signature = new FEFunctionSignature(fn.functionName(), - argTypes.toArray(new ScalarType[argTypes.size()]), fn.getReturnType()); + fn.getArgs(), fn.getReturnType()); FEFunctionInvoker invoker = getFunction(signature); if (invoker != null) { try { @@ -124,8 +120,8 @@ public enum ExpressionFunctions { continue; } - ScalarType[] argTypes1 = invoker.getSignature().getArgTypes(); - ScalarType[] argTypes2 = signature.getArgTypes(); + Type[] argTypes1 = invoker.getSignature().getArgTypes(); + Type[] argTypes2 = signature.getArgTypes(); if (!Arrays.equals(argTypes1, argTypes2)) { continue; @@ -161,12 +157,12 @@ public enum ExpressionFunctions { if (annotation != null) { String name = annotation.name(); Type returnType = Type.fromPrimitiveType(PrimitiveType.valueOf(annotation.returnType())); - List argTypes = new ArrayList<>(); + List argTypes = new ArrayList<>(); for (String type : annotation.argTypes()) { argTypes.add(ScalarType.createType(type)); } FEFunctionSignature signature = new FEFunctionSignature(name, - argTypes.toArray(new ScalarType[argTypes.size()]), returnType); + argTypes.toArray(new Type[argTypes.size()]), returnType); mapBuilder.put(name, new FEFunctionInvoker(method, signature)); } } @@ -229,7 +225,7 @@ public enum ExpressionFunctions { throw new AnalysisException("Function's args doesn't match."); } - final ScalarType argType = signature.getArgTypes()[typeIndex]; + final Type argType = signature.getArgTypes()[typeIndex]; LiteralExpr[] exprs; if (argType.isStringType()) { exprs = new StringLiteral[args.size()]; @@ -259,16 +255,16 @@ public enum ExpressionFunctions { public static class FEFunctionSignature { private final String name; - private final ScalarType[] argTypes; + private final Type[] argTypes; private final Type returnType; - public FEFunctionSignature(String name, ScalarType[] argTypes, Type returnType) { + public FEFunctionSignature(String name, Type[] argTypes, Type returnType) { this.name = name; this.argTypes = argTypes; this.returnType = returnType; } - public ScalarType[] getArgTypes() { + public Type[] getArgTypes() { return argTypes; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/ArrayType.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/ArrayType.java index 8ad8bb9935..04775c2bf6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/ArrayType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/ArrayType.java @@ -113,7 +113,7 @@ public class ArrayType extends Type { return false; } ArrayType otherArrayType = (ArrayType) other; - return otherArrayType.itemType.equals(itemType) && otherArrayType.containsNull == containsNull; + return otherArrayType.itemType.equals(itemType); } public static boolean canCastTo(ArrayType type, ArrayType targetType) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/rewrite/FEFunctions.java b/fe/fe-core/src/main/java/org/apache/doris/rewrite/FEFunctions.java index fb69a19a4c..b2463d71d2 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/rewrite/FEFunctions.java +++ b/fe/fe-core/src/main/java/org/apache/doris/rewrite/FEFunctions.java @@ -562,8 +562,19 @@ public class FEFunctions { } @FEFunctionList({ + @FEFunction(name = "array", argTypes = {"BOOLEAN"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"TINYINT"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"SMALLINT"}, returnType = "ARRAY"), @FEFunction(name = "array", argTypes = {"INT"}, returnType = "ARRAY"), - @FEFunction(name = "array", argTypes = {"VARCHAR"}, returnType = "ARRAY") + @FEFunction(name = "array", argTypes = {"BIGINT"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"LARGEINT"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"DATETIME"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"DATE"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"FLOAT"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"DOUBLE"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"DECIMALV2"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"VARCHAR"}, returnType = "ARRAY"), + @FEFunction(name = "array", argTypes = {"STRING"}, returnType = "ARRAY") }) public static ArrayLiteral array(LiteralExpr... exprs) throws AnalysisException { return new ArrayLiteral(exprs); diff --git a/regression-test/data/query/sql_functions/array_functions/test_array_functions_by_literal.out b/regression-test/data/query/sql_functions/array_functions/test_array_functions_by_literal.out new file mode 100644 index 0000000000..28c69d2f55 --- /dev/null +++ b/regression-test/data/query/sql_functions/array_functions/test_array_functions_by_literal.out @@ -0,0 +1,100 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !sql -- +true + +-- !sql -- +false + +-- !sql -- +true + +-- !sql -- +\N + +-- !sql -- +false + +-- !sql -- +\N + +-- !sql -- +\N + +-- !sql -- +\N + +-- !sql -- +1 + +-- !sql -- +3 + +-- !sql -- +0 + +-- !sql -- +2 + +-- !sql -- +\N + +-- !sql -- +0 + +-- !sql -- +\N + +-- !sql -- +\N + +-- !sql -- +\N + +-- !sql -- +1 + +-- !sql -- +3 + +-- !sql -- +\N + +-- !sql -- +3 + +-- !sql -- +\N + +-- !sql -- +\N + +-- !sql -- +2 + +-- !sql -- +\N + +-- !sql -- +1 + +-- !sql -- +3 + +-- !sql -- +\N + +-- !sql -- +3 + +-- !sql -- +\N + +-- !sql -- +\N + +-- !sql -- +2 + +-- !sql -- +\N + diff --git a/regression-test/suites/query/sql_functions/array_functions/test_array_functions_by_literal.groovy b/regression-test/suites/query/sql_functions/array_functions/test_array_functions_by_literal.groovy new file mode 100644 index 0000000000..c4349fd560 --- /dev/null +++ b/regression-test/suites/query/sql_functions/array_functions/test_array_functions_by_literal.groovy @@ -0,0 +1,62 @@ +// 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. + +suite("test_array_functions_by_literal", "all") { + sql "set enable_vectorized_engine = true" + sql "set enable_array_type = true" + + // array_contains function + qt_sql "select array_contains([1,2,3], 1)" + qt_sql "select array_contains([1,2,3], 4)" + qt_sql "select array_contains([1,2,3,NULL], 1)" + qt_sql "select array_contains([1,2,3,NULL], NULL)" + qt_sql "select array_contains([], 1)" + qt_sql "select array_contains([], NULL)" + qt_sql "select array_contains(NULL, 1)" + qt_sql "select array_contains(NULL, NULL)" + + // array_position function + qt_sql "select array_position([1,2,3], 1)" + qt_sql "select array_position([1,2,3], 3)" + qt_sql "select array_position([1,2,3], 4)" + qt_sql "select array_position([NULL,2,3], 2)" + qt_sql "select array_position([NULL,2,3], NULL)" + qt_sql "select array_position([], 1)" + qt_sql "select array_position([], NULL)" + qt_sql "select array_position(NULL, 1)" + qt_sql "select array_position(NULL, NULL)" + + // element_at function + qt_sql "select element_at([1,2,3], 1)" + qt_sql "select element_at([1,2,3], 3)" + qt_sql "select element_at([1,2,3], 4)" + qt_sql "select element_at([1,2,3], -1)" + qt_sql "select element_at([1,2,3], NULL)" + qt_sql "select element_at([1,2,NULL], 3)" + qt_sql "select element_at([1,2,NULL], 2)" + qt_sql "select element_at([], -1)" + + // array subscript function + qt_sql "select [1,2,3][1]" + qt_sql "select [1,2,3][3]" + qt_sql "select [1,2,3][4]" + qt_sql "select [1,2,3][-1]" + qt_sql "select [1,2,3][NULL]" + qt_sql "select [1,2,NULL][3]" + qt_sql "select [1,2,NULL][2]" + qt_sql "select [][-1]" +}