diff --git a/be/src/vec/CMakeLists.txt b/be/src/vec/CMakeLists.txt index 6efea10138..3f11b9d55d 100644 --- a/be/src/vec/CMakeLists.txt +++ b/be/src/vec/CMakeLists.txt @@ -174,6 +174,7 @@ set(VEC_FILES functions/array/function_array_remove.cpp functions/array/function_array_union.cpp functions/array/function_array_except.cpp + functions/array/function_array_exists.cpp functions/array/function_array_intersect.cpp functions/array/function_array_slice.cpp functions/array/function_array_difference.cpp diff --git a/be/src/vec/functions/array/function_array_exists.cpp b/be/src/vec/functions/array/function_array_exists.cpp new file mode 100644 index 0000000000..4f4fa593e5 --- /dev/null +++ b/be/src/vec/functions/array/function_array_exists.cpp @@ -0,0 +1,90 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace doris::vectorized { + +// array_exists([1, 2, 3, 0]) -> [1, 1, 1, 0] +class FunctionArrayExists : public IFunction { +public: + static constexpr auto name = "array_exists"; + + static FunctionPtr create() { return std::make_shared(); } + + String get_name() const override { return name; } + + size_t get_number_of_arguments() const override { return 1; } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + DCHECK(is_array(arguments[0])) + << "first argument for function: " << name << " should be DataTypeArray" + << " and arguments[0] is " << arguments[0]->get_name(); + return arguments[0]; + } + + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) override { + // 1. get first array column + const auto first_column = + block.get_by_position(arguments[0]).column->convert_to_full_column_if_const(); + const ColumnArray& first_col_array = assert_cast(*first_column); + const auto& first_off_data = assert_cast( + first_col_array.get_offsets_column()); + + const auto& nested_nullable_column = + assert_cast(*first_col_array.get_data_ptr()); + const auto nested_column = nested_nullable_column.get_nested_column_ptr(); + const size_t nested_column_size = nested_column->size(); + MutableColumnPtr result_null_map = + nested_nullable_column.get_null_map_column_ptr()->clone_resized(nested_column_size); + + // 2. compute result + MutableColumnPtr result_column = ColumnUInt8::create(nested_column_size, 0); + auto* __restrict result_column_data = + assert_cast(*result_column).get_data().data(); + MutableColumnPtr result_offset_column = first_off_data.clone_resized(first_off_data.size()); + const auto* __restrict nested_column_data = + assert_cast(*nested_column).get_data().data(); + + for (size_t row = 0; row < nested_column_size; ++row) { + result_column_data[row] = nested_column_data[row] != 0; + } + + ColumnPtr result_nullalble_column = + ColumnNullable::create(std::move(result_column), std::move(result_null_map)); + ColumnPtr column_array = + ColumnArray::create(result_nullalble_column, std::move(result_offset_column)); + block.replace_by_position(result, column_array); + return Status::OK(); + } +}; + +void register_function_array_exists(SimpleFunctionFactory& factory) { + factory.register_function(); +} + +} // namespace doris::vectorized diff --git a/be/src/vec/functions/array/function_array_register.cpp b/be/src/vec/functions/array/function_array_register.cpp index 044b3db09d..8d7ed301ea 100644 --- a/be/src/vec/functions/array/function_array_register.cpp +++ b/be/src/vec/functions/array/function_array_register.cpp @@ -22,6 +22,7 @@ namespace doris::vectorized { +void register_function_array_exists(SimpleFunctionFactory&); void register_function_array_element(SimpleFunctionFactory&); void register_function_array_index(SimpleFunctionFactory&); void register_function_array_size(SimpleFunctionFactory&); @@ -49,6 +50,7 @@ void register_function_array_zip(SimpleFunctionFactory&); void register_function_array_pushfront(SimpleFunctionFactory& factory); void register_function_array(SimpleFunctionFactory& factory) { + register_function_array_exists(factory); register_function_array_element(factory); register_function_array_index(factory); register_function_array_size(factory); diff --git a/docs/en/docs/sql-manual/sql-functions/array-functions/array_exists.md b/docs/en/docs/sql-manual/sql-functions/array-functions/array_exists.md new file mode 100644 index 0000000000..6ff0daa12c --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/array-functions/array_exists.md @@ -0,0 +1,114 @@ +--- +{ + "title": "array_exists", + "language": "en" +} +--- + + + +## array_exists + + + +array_exists(lambda,array1,array2....) +array_exists(array1) + + + +### description + +Use an optional lambda expression as an input parameter to perform corresponding expression calculations on the internal data of other input ARRAY parameters. Returns 1 when the calculation returns something other than 0; otherwise returns 0. +There are one or more parameters input in the lambda expression, which must be consistent with the number of input array columns later. Legal scalar functions can be executed in lambda, aggregate functions, etc. are not supported. +When lambda expression is not used as a parameter, array1 is used as the calculation result. + +``` +array_exists(x->x, array1); +array_exists(x->(x%2 = 0), array1); +array_exists(x->(abs(x)-1), array1); +array_exists((x,y)->(x = y), array1, array2); +array_exists(array1); +``` + +### example + +```sql + +mysql [test]>select *, array_exists(x->x>1,[1,2,3]) from array_test2 order by id; ++------+-----------------+-------------------------+-----------------------------------------------+ +| id | c_array1 | c_array2 | array_exists([x] -> x(0) > 1, ARRAY(1, 2, 3)) | ++------+-----------------+-------------------------+-----------------------------------------------+ +| 1 | [1, 2, 3, 4, 5] | [10, 20, -40, 80, -100] | [0, 1, 1] | +| 2 | [6, 7, 8] | [10, 12, 13] | [0, 1, 1] | +| 3 | [1] | [-100] | [0, 1, 1] | +| 4 | NULL | NULL | [0, 1, 1] | ++------+-----------------+-------------------------+-----------------------------------------------+ +4 rows in set (0.02 sec) + +mysql [test]>select c_array1, c_array2, array_exists(x->x%2=0,[1,2,3]) from array_test2 order by id; ++-----------------+-------------------------+---------------------------------------------------+ +| c_array1 | c_array2 | array_exists([x] -> x(0) % 2 = 0, ARRAY(1, 2, 3)) | ++-----------------+-------------------------+---------------------------------------------------+ +| [1, 2, 3, 4, 5] | [10, 20, -40, 80, -100] | [0, 1, 0] | +| [6, 7, 8] | [10, 12, 13] | [0, 1, 0] | +| [1] | [-100] | [0, 1, 0] | +| NULL | NULL | [0, 1, 0] | ++-----------------+-------------------------+---------------------------------------------------+ +4 rows in set (0.02 sec) + +mysql [test]>select c_array1, c_array2, array_exists(x->abs(x)-1,[1,2,3]) from array_test2 order by id; ++-----------------+-------------------------+----------------------------------------------------+ +| c_array1 | c_array2 | array_exists([x] -> abs(x(0)) - 1, ARRAY(1, 2, 3)) | ++-----------------+-------------------------+----------------------------------------------------+ +| [1, 2, 3, 4, 5] | [10, 20, -40, 80, -100] | [0, 1, 1, 1, 1] | +| [6, 7, 8] | [10, 12, 13] | [1, 1, 1] | +| [1, NULL] | [-100] | [0, NULL] | +| NULL | NULL | NULL | ++-----------------+-------------------------+----------------------------------------------------+ +4 rows in set (0.02 sec) + +mysql [test]>select c_array1, c_array2, array_exists((x,y)->x>y,c_array1,c_array2) from array_test2 order by id; ++-----------------+-------------------------+-------------------------------------------------------------+ +| c_array1 | c_array2 | array_exists([x, y] -> x(0) > y(1), `c_array1`, `c_array2`) | ++-----------------+-------------------------+-------------------------------------------------------------+ +| [1, 2, 3, 4, 5] | [10, 20, -40, 80, -100] | [0, 0, 1, 0, 1] | +| [6, 7, 8] | [10, 12, 13] | [0, 0, 0] | +| [1] | [-100] | [1] | +| NULL | NULL | NULL | ++-----------------+-------------------------+-------------------------------------------------------------+ +4 rows in set (0.02 sec) + +mysql [test]>select *, array_exists(c_array1) from array_test2 order by id; ++------+-----------------+-------------------------+--------------------------+ +| id | c_array1 | c_array2 | array_exists(`c_array1`) | ++------+-----------------+-------------------------+--------------------------+ +| 1 | [1, 2, 3, 0, 5] | [10, 20, -40, 80, -100] | [1, 1, 1, 0, 1] | +| 2 | [6, 7, 8] | [10, 12, 13] | [1, 1, 1] | +| 3 | [0, NULL] | [-100] | [0, NULL] | +| 4 | NULL | NULL | NULL | ++------+-----------------+-------------------------+--------------------------+ +4 rows in set (0.02 sec) + +``` + +### keywords + +ARRAY,ARRAY_EXISTS + diff --git a/docs/sidebars.json b/docs/sidebars.json index a901489582..cff67c5099 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -301,6 +301,7 @@ "sql-manual/sql-functions/array-functions/array_compact", "sql-manual/sql-functions/array-functions/array_concat", "sql-manual/sql-functions/array-functions/array_zip", + "sql-manual/sql-functions/array-functions/array_exists", "sql-manual/sql-functions/array-functions/arrays_overlap", "sql-manual/sql-functions/array-functions/countequal", "sql-manual/sql-functions/array-functions/element_at" diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array_exists.md b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array_exists.md new file mode 100644 index 0000000000..8394c27c4d --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array_exists.md @@ -0,0 +1,113 @@ +--- +{ + "title": "array_exists", + "language": "zh-CN" +} +--- + + + +## array_exists + + + +array_exists(lambda,array1,array2....) +array_exists(array1) + + + +### description + +使用一个可选lambda表达式作为输入参数,对其他的输入ARRAY参数的内部数据做对应表达式计算。当计算返回非0时,返回1;否则返回0。 +在lambda表达式中输入的参数为1个或多个,必须和后面的输入array列数量一致。在lambda中可以执行合法的标量函数,不支持聚合函数等。 +在没有使用lambda作为参数时,array1作为计算结果。 + +``` +array_exists(x->x, array1); +array_exists(x->(x%2 = 0), array1); +array_exists(x->(abs(x)-1), array1); +array_exists((x,y)->(x = y), array1, array2); +array_exists(array1); +``` + +### example + +```sql + +mysql [test]>select *, array_exists(x->x>1,[1,2,3]) from array_test2 order by id; ++------+-----------------+-------------------------+-----------------------------------------------+ +| id | c_array1 | c_array2 | array_exists([x] -> x(0) > 1, ARRAY(1, 2, 3)) | ++------+-----------------+-------------------------+-----------------------------------------------+ +| 1 | [1, 2, 3, 4, 5] | [10, 20, -40, 80, -100] | [0, 1, 1] | +| 2 | [6, 7, 8] | [10, 12, 13] | [0, 1, 1] | +| 3 | [1] | [-100] | [0, 1, 1] | +| 4 | NULL | NULL | [0, 1, 1] | ++------+-----------------+-------------------------+-----------------------------------------------+ +4 rows in set (0.02 sec) + +mysql [test]>select c_array1, c_array2, array_exists(x->x%2=0,[1,2,3]) from array_test2 order by id; ++-----------------+-------------------------+---------------------------------------------------+ +| c_array1 | c_array2 | array_exists([x] -> x(0) % 2 = 0, ARRAY(1, 2, 3)) | ++-----------------+-------------------------+---------------------------------------------------+ +| [1, 2, 3, 4, 5] | [10, 20, -40, 80, -100] | [0, 1, 0] | +| [6, 7, 8] | [10, 12, 13] | [0, 1, 0] | +| [1] | [-100] | [0, 1, 0] | +| NULL | NULL | [0, 1, 0] | ++-----------------+-------------------------+---------------------------------------------------+ +4 rows in set (0.02 sec) + +mysql [test]>select c_array1, c_array2, array_exists(x->abs(x)-1,[1,2,3]) from array_test2 order by id; ++-----------------+-------------------------+----------------------------------------------------+ +| c_array1 | c_array2 | array_exists([x] -> abs(x(0)) - 1, ARRAY(1, 2, 3)) | ++-----------------+-------------------------+----------------------------------------------------+ +| [1, 2, 3, 4, 5] | [10, 20, -40, 80, -100] | [0, 1, 1, 1, 1] | +| [6, 7, 8] | [10, 12, 13] | [1, 1, 1] | +| [1, NULL] | [-100] | [0, NULL] | +| NULL | NULL | NULL | ++-----------------+-------------------------+----------------------------------------------------+ +4 rows in set (0.02 sec) + +mysql [test]>select c_array1, c_array2, array_exists((x,y)->x>y,c_array1,c_array2) from array_test2 order by id; ++-----------------+-------------------------+-------------------------------------------------------------+ +| c_array1 | c_array2 | array_exists([x, y] -> x(0) > y(1), `c_array1`, `c_array2`) | ++-----------------+-------------------------+-------------------------------------------------------------+ +| [1, 2, 3, 4, 5] | [10, 20, -40, 80, -100] | [0, 0, 1, 0, 1] | +| [6, 7, 8] | [10, 12, 13] | [0, 0, 0] | +| [1] | [-100] | [1] | +| NULL | NULL | NULL | ++-----------------+-------------------------+-------------------------------------------------------------+ +4 rows in set (0.02 sec) + +mysql [test]>select *, array_exists(c_array1) from array_test2 order by id; ++------+-----------------+-------------------------+--------------------------+ +| id | c_array1 | c_array2 | array_exists(`c_array1`) | ++------+-----------------+-------------------------+--------------------------+ +| 1 | [1, 2, 3, 0, 5] | [10, 20, -40, 80, -100] | [1, 1, 1, 0, 1] | +| 2 | [6, 7, 8] | [10, 12, 13] | [1, 1, 1] | +| 3 | [0, NULL] | [-100] | [0, NULL] | +| 4 | NULL | NULL | NULL | ++------+-----------------+-------------------------+--------------------------+ +4 rows in set (0.02 sec) + +``` + +### keywords + +ARRAY,ARRAY_EXISTS diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java index 0f8c911d69..f538e85cc6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java @@ -1047,6 +1047,23 @@ public class FunctionCallExpr extends Expr { uncheckedCastChild(compatibleType, i); } } + + if (fnName.getFunction().equalsIgnoreCase("array_exists")) { + Type[] newArgTypes = new Type[1]; + if (!(getChild(0) instanceof CastExpr)) { + Expr castExpr = getChild(0).castTo(ArrayType.create(Type.BOOLEAN, true)); + this.setChild(0, castExpr); + newArgTypes[0] = castExpr.getType(); + } + + fn = getBuiltinFunction(fnName.getFunction(), newArgTypes, + Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF); + if (fn == null) { + LOG.warn("fn {} not exists", this.toSqlImpl()); + throw new AnalysisException(getFunctionNotFoundError(collectChildReturnTypes())); + } + fn.setReturnType(getChild(0).getType()); + } } // Provide better error message for some aggregate builtins. These can be diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/LambdaFunctionCallExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/LambdaFunctionCallExpr.java index 9b5f7c0b99..7b7021798d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/LambdaFunctionCallExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/LambdaFunctionCallExpr.java @@ -34,7 +34,10 @@ import java.util.List; public class LambdaFunctionCallExpr extends FunctionCallExpr { public static final ImmutableSet LAMBDA_FUNCTION_SET = new ImmutableSortedSet.Builder( - String.CASE_INSENSITIVE_ORDER).add("array_map").add("array_filter").build(); + String.CASE_INSENSITIVE_ORDER).add("array_map").add("array_filter").add("array_exists").build(); + + public static final ImmutableSet LAMBDA_MAPPED_FUNCTION_SET = new ImmutableSortedSet.Builder( + String.CASE_INSENSITIVE_ORDER).add("array_exists").build(); private static final Logger LOG = LogManager.getLogger(LambdaFunctionCallExpr.class); @@ -97,8 +100,41 @@ public class LambdaFunctionCallExpr extends FunctionCallExpr { throw new AnalysisException(getFunctionNotFoundError(collectChildReturnTypes())); } fn.setReturnType(ArrayType.create(lambda.getChild(0).getType(), true)); - } - if (fnName.getFunction().equalsIgnoreCase("array_filter")) { + } else if (fnName.getFunction().equalsIgnoreCase("array_exists")) { + if (fnParams.exprs() == null || fnParams.exprs().size() < 1) { + throw new AnalysisException("The " + fnName.getFunction() + " function must have at least two params"); + } + // array_exists(x->x>3, [1,2,3,6,34,3,11]) + // ---> array_exists(array_map(x->x>3, [1,2,3,6,34,3,11])) + Type[] newArgTypes = new Type[1]; + if (getChild(childSize - 1) instanceof LambdaFunctionExpr) { + List params = new ArrayList<>(); + for (int i = 0; i <= childSize - 1; ++i) { + params.add(getChild(i)); + } + LambdaFunctionCallExpr arrayMapFunc = new LambdaFunctionCallExpr("array_map", + params); + arrayMapFunc.analyzeImpl(analyzer); + Expr castExpr = arrayMapFunc.castTo(ArrayType.create(Type.BOOLEAN, true)); + this.clearChildren(); + this.addChild(castExpr); + newArgTypes[0] = castExpr.getType(); + } + + if (!(getChild(0) instanceof CastExpr)) { + Expr castExpr = getChild(0).castTo(ArrayType.create(Type.BOOLEAN, true)); + this.setChild(0, castExpr); + newArgTypes[0] = castExpr.getType(); + } + + fn = getBuiltinFunction(fnName.getFunction(), newArgTypes, + Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF); + if (fn == null) { + LOG.warn("fn {} not exists", this.toSqlImpl()); + throw new AnalysisException(getFunctionNotFoundError(collectChildReturnTypes())); + } + fn.setReturnType(getChild(0).getType()); + } else if (fnName.getFunction().equalsIgnoreCase("array_filter")) { if (fnParams.exprs() == null || fnParams.exprs().size() != 2) { throw new AnalysisException("The " + fnName.getFunction() + " function must have at least two params"); } @@ -139,6 +175,11 @@ public class LambdaFunctionCallExpr extends FunctionCallExpr { @Override protected void toThrift(TExprNode msg) { - msg.node_type = TExprNodeType.LAMBDA_FUNCTION_CALL_EXPR; + FunctionName fnName = getFnName(); + if (LAMBDA_MAPPED_FUNCTION_SET.contains(fnName.getFunction().toLowerCase())) { + msg.node_type = TExprNodeType.FUNCTION_CALL; + } else { + msg.node_type = TExprNodeType.LAMBDA_FUNCTION_CALL_EXPR; + } } } diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index 870690f54b..95d48f9bac 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -612,6 +612,25 @@ visible_functions = [ [['array_filter'], 'ARRAY_DATETIMEV2',['ARRAY_DATETIMEV2', 'ARRAY_BOOLEAN'], ''], [['array_filter'], 'ARRAY_DATEV2',['ARRAY_DATEV2', 'ARRAY_BOOLEAN'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_BOOLEAN'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_TINYINT'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_SMALLINT'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_INT'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_BIGINT'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_LARGEINT'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_DATETIME'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_DATE'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_DATETIMEV2'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_DATEV2'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_FLOAT'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_DOUBLE'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_DECIMALV2'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_DECIMAL32'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_DECIMAL64'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_DECIMAL128'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_VARCHAR'], ''], + [['array_exists'], 'ARRAY_BOOLEAN', ['ARRAY_STRING'], ''], + [['array_pushfront'], 'ARRAY_BOOLEAN', ['ARRAY_BOOLEAN', 'BOOLEAN'], 'ALWAYS_NULLABLE'], [['array_pushfront'], 'ARRAY_TINYINT', ['ARRAY_TINYINT', 'TINYINT'], 'ALWAYS_NULLABLE'], [['array_pushfront'], 'ARRAY_SMALLINT', ['ARRAY_SMALLINT', 'SMALLINT'], 'ALWAYS_NULLABLE'], diff --git a/regression-test/data/query_p0/sql_functions/array_functions/test_array_exists_function.out b/regression-test/data/query_p0/sql_functions/array_functions/test_array_exists_function.out new file mode 100644 index 0000000000..2e53c689f5 --- /dev/null +++ b/regression-test/data/query_p0/sql_functions/array_functions/test_array_exists_function.out @@ -0,0 +1,72 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select_1 -- +1 [1, 2, 3, 4, 5] [10, 20, -40, 80, -100] +2 [6, 7, 8] [10, 12, 13] +3 [1] [-100] +4 \N \N + +-- !select_2 -- +1 [1, 2, 3, 4, 5] [10, 20, -40, 80, -100] [0, 0, 1] +2 [6, 7, 8] [10, 12, 13] [0, 0, 1] +3 [1] [-100] [0, 0, 1] +4 \N \N [0, 0, 1] + +-- !select_3 -- +1 [1, 2, 3, 4, 5] [10, 20, -40, 80, -100] [1, 1, 1] +2 [6, 7, 8] [10, 12, 13] [1, 1, 1] +3 [1] [-100] [1, 1, 1] +4 \N \N [1, 1, 1] + +-- !select_4 -- +[1, 2, 3, 4, 5] [10, 20, -40, 80, -100] [0, 1, 0] +[6, 7, 8] [10, 12, 13] [0, 1, 0] +[1] [-100] [0, 1, 0] +\N \N [0, 1, 0] + +-- !select_5 -- +[1, 2, 3, 4, 5] [10, 20, -40, 80, -100] [1, 1, 1, 1, 1] +[6, 7, 8] [10, 12, 13] [1, 1, 1] +[1] [-100] [1] +\N \N \N + +-- !select_6 -- +[1, 2, 3, 4, 5] [10, 20, -40, 80, -100] [1, 1, 1, 1, 1] +[6, 7, 8] [10, 12, 13] [1, 1, 1] +[1] [-100] [1] +\N \N \N + +-- !select_7 -- +[1, 2, 3, 4, 5] [10, 20, -40, 80, -100] [0, 0, 0, 1, 1] +[6, 7, 8] [10, 12, 13] [1, 1, 1] +[1] [-100] [0] +\N \N \N + +-- !select_8 -- +[] + +-- !select_9 -- +[NULL] + +-- !select_10 -- +[1, 0] + +-- !select_11 -- +[1, 0, 0] + +-- !select_12 -- +1 [1, 2, 3, 4, 5] [10, 20, -40, 80, -100] [1, 1, 1] +2 [6, 7, 8] [10, 12, 13] [1, 1, 1] +3 [1] [-100] [1, 1, 1] +4 \N \N [1, 1, 1] + +-- !select_13 -- +[1, 2, 3, 4, 5] [10, 20, -40, 80, -100] [1, 1, 1, 1, 1] +[6, 7, 8] [10, 12, 13] [1, 1, 1] +[1] [-100] [1] +\N \N \N + +-- !select_14 -- +[] + +-- !select_15 -- +[NULL, 1, 1] diff --git a/regression-test/suites/query_p0/sql_functions/array_functions/test_array_exists_function.groovy b/regression-test/suites/query_p0/sql_functions/array_functions/test_array_exists_function.groovy new file mode 100644 index 0000000000..c4f38834ad --- /dev/null +++ b/regression-test/suites/query_p0/sql_functions/array_functions/test_array_exists_function.groovy @@ -0,0 +1,63 @@ +// 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_exists_function") { + + def tableName = "array_exists_table" + sql "DROP TABLE IF EXISTS ${tableName}" + sql """ + CREATE TABLE IF NOT EXISTS `${tableName}` ( + `id` int(11) NULL, + `c_array1` array NULL, + `c_array2` array NULL + ) ENGINE=OLAP + DUPLICATE KEY(`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1", + "storage_format" = "V2" + ) + """ + + + sql """INSERT INTO ${tableName} values + (1, [1,2,3,4,5], [10,20,-40,80,-100]), + (2, [6,7,8],[10,12,13]), (3, [1],[-100]), (4, null,null) + """ + qt_select_1 "select * from ${tableName} order by id;" + + qt_select_2 "select *, array_exists(x->x>2,[1,2,3]) from ${tableName} order by id;" + qt_select_3 "select *, array_exists(x->x+1,[1,2,3]) from ${tableName} order by id;" + qt_select_4 "select c_array1, c_array2, array_exists(x->x%2=0,[1,2,3]) from ${tableName} order by id;" + + qt_select_5 "select c_array1, c_array2, array_exists(x->x,c_array1) from ${tableName} order by id;" + qt_select_6 "select c_array1, c_array2, array_exists(x->x+2,c_array1) from ${tableName} order by id;" + qt_select_7 "select c_array1, c_array2, array_exists(x->power(x,2)>10,c_array1) from ${tableName} order by id;" + + qt_select_8 "select array_exists(x -> x,[]);" + qt_select_9 "select array_exists(x -> x,[null]);" + qt_select_10 "select array_exists(x -> x,[1, 0]);" + qt_select_11 "select array_exists(x -> x is null, [null, 1, 2]);" + + qt_select_12 "select *, array_exists([1,2,3]) from ${tableName} order by id;" + qt_select_13 "select c_array1, c_array2, array_exists(c_array1) from ${tableName} order by id;" + + qt_select_14 "select array_exists([]);" + qt_select_15 "select array_exists([null, 1, 2]);" + + sql "DROP TABLE IF EXISTS ${tableName}" +}