From 3617195f007dde5c64141444d56538e99621aef3 Mon Sep 17 00:00:00 2001 From: zhangstar333 <2561612514@qq.com> Date: Tue, 5 Sep 2023 23:23:15 +0800 Subject: [PATCH 1/4] [BUG](view) fix can't create view with lambda function --- .../java/org/apache/doris/analysis/Expr.java | 5 +++ .../doris/analysis/FunctionCallExpr.java | 9 +++- .../analysis/LambdaFunctionCallExpr.java | 26 ++++++++++++ .../doris/analysis/LambdaFunctionExpr.java | 15 ++++++- .../data/ddl_p0/test_create_view.out | 26 ++++++++++++ .../suites/ddl_p0/test_create_view.groovy | 42 +++++++++++++++++++ 6 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 regression-test/data/ddl_p0/test_create_view.out diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java index 4ce82186067a36..1b583425e11bad 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java @@ -1845,6 +1845,11 @@ private boolean findSlotRefByName(String colName) { if (slot.getColumnName() != null && slot.getColumnName().equals(colName)) { return true; } + } else if (this instanceof ColumnRefExpr) { + ColumnRefExpr slot = (ColumnRefExpr) this; + if (slot.getName() != null && slot.getName().equals(colName)) { + return true; + } } return false; } 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 53e3458c3e7b02..e8be76dd019893 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 @@ -786,7 +786,14 @@ protected void toThrift(TExprNode msg) { } msg.setAggExpr(aggFnParams.createTAggregateExpr(isMergeAggFn)); } else { - msg.node_type = TExprNodeType.FUNCTION_CALL; + // array_filter(array, boolean) only implement as lambda function + // eg: SELECT array_filter(`array_d`, array_map(x -> (x >= 1), `array_d`)) + // can't as a normal function for BE, need handle by lambda function call expr + if (fnName.getFunction().equalsIgnoreCase("array_filter")) { + msg.node_type = TExprNodeType.LAMBDA_FUNCTION_CALL_EXPR; + } else { + msg.node_type = TExprNodeType.FUNCTION_CALL; + } } } 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 33a66570e52769..c05e0a47ef7da7 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 @@ -263,4 +263,30 @@ protected void toThrift(TExprNode msg) { msg.node_type = TExprNodeType.LAMBDA_FUNCTION_CALL_EXPR; } } + + @Override + public String toSqlImpl() { + StringBuilder sb = new StringBuilder(); + sb.append(getFnName().getFunction()); + sb.append("("); + int childSize = children.size(); + Expr lastExpr = getChild(childSize - 1); + boolean lastIsLambdaExpr = (lastExpr instanceof LambdaFunctionExpr); + if (lastIsLambdaExpr) { + sb.append(lastExpr.toSql()); + sb.append(", "); + } + for (int i = 0; i < childSize - 1; ++i) { + sb.append(getChild(i).toSql()); + if (i != childSize - 2) { + sb.append(", "); + } + } + if (lastIsLambdaExpr == false) { + sb.append(", "); + sb.append(lastExpr.toSql()); + } + sb.append(")"); + return sb.toString(); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/LambdaFunctionExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/LambdaFunctionExpr.java index 15c37ad85052ed..e2e7b90bfb2077 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/LambdaFunctionExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/LambdaFunctionExpr.java @@ -115,7 +115,20 @@ protected void analyzeImpl(Analyzer analyzer) throws AnalysisException { @Override protected String toSqlImpl() { - return String.format("%s -> %s", names.toString(), getChild(0).toSql()); + String nameStr = ""; + Expr lambdaExpr = slotExpr.get(0); + int exprSize = names.size(); + for (int i = 0; i < exprSize; ++i) { + nameStr = nameStr + names.get(i); + if (i != exprSize - 1) { + nameStr = nameStr + ","; + } + } + if (exprSize > 1) { + nameStr = "(" + nameStr + ")"; + } + String res = String.format("%s -> %s", nameStr, lambdaExpr.toSql()); + return res; } @Override diff --git a/regression-test/data/ddl_p0/test_create_view.out b/regression-test/data/ddl_p0/test_create_view.out new file mode 100644 index 00000000000000..f55b7fa59819d5 --- /dev/null +++ b/regression-test/data/ddl_p0/test_create_view.out @@ -0,0 +1,26 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !test_view_1 -- +1 [1, 2, 3] +2 [10, -2, 8] +3 [-1, 20, 0] + +-- !test_view_2 -- +1 [1, 2, 3] [1, 1, 1] +2 [10, -2, 8] [1, 0, 1] +3 [-1, 20, 0] [0, 1, 0] + +-- !test_view_3 -- +1 [1, 2, 3] [1, 2, 3] [1, 2, 3] +2 [10, -2, 8] [10, 8] [10, 8] +3 [-1, 20, 0] [20] [20] + +-- !test_view_4 -- +1 [1, 2, 3] [1, 2, 3] [1, 2, 3] +2 [10, -2, 8] [10, 8] [10, 8] +3 [-1, 20, 0] [20] [20] + +-- !test_view_5 -- +1 [1, 2, 3] [1, 1, 1] +2 [10, -2, 8] [1, 0, 1] +3 [-1, 20, 0] [0, 1, 0] + diff --git a/regression-test/suites/ddl_p0/test_create_view.groovy b/regression-test/suites/ddl_p0/test_create_view.groovy index c209d42bd358d3..a2c7090e6dcb93 100644 --- a/regression-test/suites/ddl_p0/test_create_view.groovy +++ b/regression-test/suites/ddl_p0/test_create_view.groovy @@ -111,4 +111,46 @@ suite("test_create_view") { sql """DROP VIEW IF EXISTS my_view""" sql """DROP TABLE IF EXISTS t1""" sql """DROP TABLE IF EXISTS t2""" + + + sql """DROP TABLE IF EXISTS view_baseall""" + sql """DROP VIEW IF EXISTS test_view7""" + sql """DROP VIEW IF EXISTS test_view8""" + sql """ + CREATE TABLE `view_baseall` ( + `k1` int(11) NULL, + `k3` array NULL + ) ENGINE=OLAP + DUPLICATE KEY(`k1`) + COMMENT 'OLAP' + DISTRIBUTED BY HASH(`k1`) BUCKETS 5 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1", + "is_being_synced" = "false", + "storage_format" = "V2", + "light_schema_change" = "true", + "disable_auto_compaction" = "false", + "enable_single_replica_compaction" = "false" + ); + """ + sql """insert into view_baseall values(1,[1,2,3]);""" + sql """insert into view_baseall values(2,[10,-2,8]);""" + sql """insert into view_baseall values(3,[-1,20,0]);""" + + qt_test_view_1 """ select * from view_baseall order by k1; """ + qt_test_view_2 """ select *, array_map(x->x>0,k3) from view_baseall order by k1; """ + qt_test_view_3 """ select *, array_filter(x->x>0,k3),array_filter(`k3`, array_map(x -> x > 0, `k3`)) from view_baseall order by k1; """ + + + sql """ + create view IF NOT EXISTS test_view7 (k1,k2,k3,k4) as + select *, array_filter(x->x>0,k3),array_filter(`k3`, array_map(x -> x > 0, `k3`)) from view_baseall order by k1; + """ + qt_test_view_4 """ select * from test_view7 order by k1; """ + + sql """ + create view IF NOT EXISTS test_view8 (k1,k2,k3) as + select *, array_map(x->x>0,k3) from view_baseall order by k1; + """ + qt_test_view_5 """ select * from test_view8 order by k1; """ } From c67cd238088ba4b39fb521e4a4f9e5699c2adf49 Mon Sep 17 00:00:00 2001 From: zhangstar333 <2561612514@qq.com> Date: Thu, 7 Sep 2023 13:53:53 +0800 Subject: [PATCH 2/4] add array_filter function --- .../functions/array/function_array_filter.cpp | 133 ++++++++++++++++++ .../array/function_array_register.cpp | 2 + .../array-functions/array-filter.md | 18 ++- .../array-functions/array-filter.md | 20 ++- .../doris/analysis/FunctionCallExpr.java | 9 +- .../analysis/LambdaFunctionCallExpr.java | 7 + 6 files changed, 176 insertions(+), 13 deletions(-) create mode 100644 be/src/vec/functions/array/function_array_filter.cpp diff --git a/be/src/vec/functions/array/function_array_filter.cpp b/be/src/vec/functions/array/function_array_filter.cpp new file mode 100644 index 00000000000000..d6395ed37b8e64 --- /dev/null +++ b/be/src/vec/functions/array/function_array_filter.cpp @@ -0,0 +1,133 @@ +// 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 "common/status.h" +#include "vec/aggregate_functions/aggregate_function.h" +#include "vec/columns/column.h" +#include "vec/columns/column_vector.h" +#include "vec/columns/columns_number.h" +#include "vec/core/block.h" +#include "vec/core/column_numbers.h" +#include "vec/core/column_with_type_and_name.h" +#include "vec/core/types.h" +#include "vec/data_types/data_type.h" +#include "vec/functions/array/function_array_utils.h" +#include "vec/functions/function.h" +#include "vec/functions/simple_function_factory.h" + +namespace doris { +class FunctionContext; +} // namespace doris + +namespace doris::vectorized { + +class FunctionArrayFilter : public IFunction { +public: + static constexpr auto name = "array_filter"; + static FunctionPtr create() { return std::make_shared(); } + + /// Get function name. + String get_name() const override { return name; } + + bool is_variadic() const override { return false; } + + size_t get_number_of_arguments() const override { return 2; } + + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + DCHECK(is_array(arguments[0])) + << "First argument for function: " << name + << " should be DataTypeArray but it has type " << 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 { + //TODO: maybe need optimize not convert + auto first_column = + block.get_by_position(arguments[0]).column->convert_to_full_column_if_const(); + auto second_column = + block.get_by_position(arguments[1]).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()) + .get_data(); + const auto& first_nested_nullable_column = + assert_cast(*first_col_array.get_data_ptr()); + + const ColumnArray& second_col_array = assert_cast(*second_column); + const auto& second_off_data = assert_cast( + second_col_array.get_offsets_column()) + .get_data(); + const auto& second_nested_null_map_data = + assert_cast(*second_col_array.get_data_ptr()) + .get_null_map_column() + .get_data(); + const auto& second_nested_column = + assert_cast(*second_col_array.get_data_ptr()) + .get_nested_column(); + const auto& second_nested_data = + assert_cast(second_nested_column).get_data(); + + auto result_data_column = first_nested_nullable_column.clone_empty(); + auto result_offset_column = ColumnArray::ColumnOffsets::create(); + auto& result_offset_data = result_offset_column->get_data(); + vectorized::IColumn::Selector selector; + selector.reserve(first_off_data.size()); + result_offset_data.reserve(input_rows_count); + + for (size_t row = 0; row < input_rows_count; ++row) { + unsigned long count = 0; + auto first_offset_start = first_off_data[row - 1]; + auto first_offset_end = first_off_data[row]; + auto second_offset_start = second_off_data[row - 1]; + auto second_offset_end = second_off_data[row]; + auto move_off = second_offset_start; + for (auto off = first_offset_start; + off < first_offset_end && move_off < second_offset_end; // not out range + ++off) { + if (second_nested_null_map_data[move_off] == 0 && // not null + second_nested_data[move_off] == 1) { // not 0 + count++; + selector.push_back(off); + } + move_off++; + } + result_offset_data.push_back(count + result_offset_data.back()); + } + first_nested_nullable_column.append_data_by_selector(result_data_column, selector); + + auto res_column = + ColumnArray::create(std::move(result_data_column), std::move(result_offset_column)); + block.replace_by_position(result, std::move(res_column)); + return Status::OK(); + } +}; + +void register_function_array_filter_function(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 0a0cb5a96ddfca..5a7c33c687a51f 100644 --- a/be/src/vec/functions/array/function_array_register.cpp +++ b/be/src/vec/functions/array/function_array_register.cpp @@ -54,6 +54,7 @@ void register_function_array_pushback(SimpleFunctionFactory& factory); void register_function_array_first_or_last_index(SimpleFunctionFactory& factory); void register_function_array_cum_sum(SimpleFunctionFactory& factory); void register_function_array_count(SimpleFunctionFactory&); +void register_function_array_filter_function(SimpleFunctionFactory&); void register_function_array(SimpleFunctionFactory& factory) { register_function_array_shuffle(factory); @@ -88,6 +89,7 @@ void register_function_array(SimpleFunctionFactory& factory) { register_function_array_first_or_last_index(factory); register_function_array_cum_sum(factory); register_function_array_count(factory); + register_function_array_filter_function(factory); } } // namespace doris::vectorized diff --git a/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md b/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md index 0a7d216fea65aa..7acd8d610c52ea 100644 --- a/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md +++ b/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md @@ -32,12 +32,16 @@ array_filter(lambda,array) + +array array_filter(array arr, array filter_column) + + ### description #### Syntax ```sql -ARRAY array_filter(lambda, ARRAY arr1, ARRAY arr2, ... ) -ARRAY array_filter(ARRAY arr) +ARRAY array_filter(lambda, ARRAY arr) +ARRAY array_filter(ARRAY arr, ARRAY filter_column) ``` Use the lambda expression as the input parameter to calculate and filter the data of the ARRAY column of the other input parameter. @@ -47,11 +51,21 @@ And filter out the values of 0 and NULL in the result. array_filter(x->x>0, array1); array_filter(x->(x+2)=10, array1); array_filter(x->(abs(x)-2)>0, array1); +array_filter(c_array,[0,1,0]); ``` ### example ```shell +mysql [test]>select c_array,array_filter(c_array,[0,1,0]) from array_test; ++-----------------+----------------------------------------------------+ +| c_array | array_filter(`c_array`, ARRAY(FALSE, TRUE, FALSE)) | ++-----------------+----------------------------------------------------+ +| [1, 2, 3, 4, 5] | [2] | +| [6, 7, 8] | [7] | +| [] | [] | +| NULL | NULL | ++-----------------+----------------------------------------------------+ mysql [test]>select array_filter(x->(x > 1),[1,2,3,0,null]); +----------------------------------------------------------------------------------------------+ diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md index 479c6cdb93859b..bc801dd2974845 100644 --- a/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md +++ b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md @@ -32,12 +32,16 @@ array_filter(lambda,array) + +array array_filter(array arr, array filter_column) + + ### description #### Syntax ```sql -ARRAY array_filter(lambda, ARRAY arr1, ARRAY arr2, ... ) -ARRAY array_filter(ARRAY arr) +ARRAY array_filter(lambda, ARRAY arr) +ARRAY array_filter(ARRAY arr, ARRAY filter_column) ``` 使用lambda表达式作为输入参数,计算筛选另外的输入参数ARRAY列的数据。 @@ -47,12 +51,22 @@ ARRAY array_filter(ARRAY arr) array_filter(x->x>0, array1); array_filter(x->(x+2)=10, array1); array_filter(x->(abs(x)-2)>0, array1); - +array_filter(c_array,[0,1,0]); ``` ### example ```shell +mysql [test]>select c_array,array_filter(c_array,[0,1,0]) from array_test; ++-----------------+----------------------------------------------------+ +| c_array | array_filter(`c_array`, ARRAY(FALSE, TRUE, FALSE)) | ++-----------------+----------------------------------------------------+ +| [1, 2, 3, 4, 5] | [2] | +| [6, 7, 8] | [7] | +| [] | [] | +| NULL | NULL | ++-----------------+----------------------------------------------------+ + mysql [test]>select array_filter(x->(x > 1),[1,2,3,0,null]); +----------------------------------------------------------------------------------------------+ | array_filter(ARRAY(1, 2, 3, 0, NULL), array_map([x] -> (x(0) > 1), ARRAY(1, 2, 3, 0, NULL))) | 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 e8be76dd019893..53e3458c3e7b02 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 @@ -786,14 +786,7 @@ protected void toThrift(TExprNode msg) { } msg.setAggExpr(aggFnParams.createTAggregateExpr(isMergeAggFn)); } else { - // array_filter(array, boolean) only implement as lambda function - // eg: SELECT array_filter(`array_d`, array_map(x -> (x >= 1), `array_d`)) - // can't as a normal function for BE, need handle by lambda function call expr - if (fnName.getFunction().equalsIgnoreCase("array_filter")) { - msg.node_type = TExprNodeType.LAMBDA_FUNCTION_CALL_EXPR; - } else { - msg.node_type = TExprNodeType.FUNCTION_CALL; - } + msg.node_type = TExprNodeType.FUNCTION_CALL; } } 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 c05e0a47ef7da7..4c9455d4e0c8d6 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 @@ -271,6 +271,10 @@ public String toSqlImpl() { sb.append("("); int childSize = children.size(); Expr lastExpr = getChild(childSize - 1); + // eg: select array_map(x->x>10, k1) from table, + // but we need analyze each param, so change the function like this in parser + // array_map(x->x>10, k1) ---> array_map(k1, x->x>10), + // so maybe the lambda expr is the end position. and need this check. boolean lastIsLambdaExpr = (lastExpr instanceof LambdaFunctionExpr); if (lastIsLambdaExpr) { sb.append(lastExpr.toSql()); @@ -282,6 +286,9 @@ public String toSqlImpl() { sb.append(", "); } } + // and some functions is only implement as a normal array function; + // but also want use as lambda function, select array_sortby(x->x,['b','a','c']); + // so we convert to: array_sortby(array('b', 'a', 'c'), array_map(x -> `x`, array('b', 'a', 'c'))) if (lastIsLambdaExpr == false) { sb.append(", "); sb.append(lastExpr.toSql()); From ccd215a75ae3c59dfd07501090550a9073e0668a Mon Sep 17 00:00:00 2001 From: zhangstar333 <2561612514@qq.com> Date: Fri, 8 Sep 2023 10:16:16 +0800 Subject: [PATCH 3/4] update docs --- .../sql-manual/sql-functions/array-functions/array-filter.md | 2 ++ .../sql-manual/sql-functions/array-functions/array-filter.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md b/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md index 7acd8d610c52ea..2b972c1a9a7a0c 100644 --- a/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md +++ b/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md @@ -33,7 +33,9 @@ array_filter(lambda,array) + array array_filter(array arr, array filter_column) + ### description diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md index bc801dd2974845..8f5ec6243a8acb 100644 --- a/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md +++ b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md @@ -33,7 +33,9 @@ array_filter(lambda,array) + array array_filter(array arr, array filter_column) + ### description From d2541dd92b0bb51360115febbdfd0ea267e14500 Mon Sep 17 00:00:00 2001 From: zhangstar333 <2561612514@qq.com> Date: Fri, 8 Sep 2023 18:23:51 +0800 Subject: [PATCH 4/4] update docs --- .../sql-manual/sql-functions/array-functions/array-filter.md | 2 +- .../sql-manual/sql-functions/array-functions/array-filter.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md b/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md index 2b972c1a9a7a0c..6bedc3ef6ccb61 100644 --- a/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md +++ b/docs/en/docs/sql-manual/sql-functions/array-functions/array-filter.md @@ -34,7 +34,7 @@ array_filter(lambda,array) -array array_filter(array arr, array filter_column) +array array_filter(array arr, array_bool filter_column) diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md index 8f5ec6243a8acb..1a0dcdff76eb79 100644 --- a/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md +++ b/docs/zh-CN/docs/sql-manual/sql-functions/array-functions/array-filter.md @@ -34,7 +34,7 @@ array_filter(lambda,array) -array array_filter(array arr, array filter_column) +array array_filter(array arr, array_bool filter_column)