This is an automated email from the ASF dual-hosted git repository. lihaopeng pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-doris.git
The following commit(s) were added to refs/heads/master by this push: new 2d83167e50 [Feature] [Lateral-View] support outer combinator of table function (#9147) 2d83167e50 is described below commit 2d83167e50069ee575ab8b6f3a9a6cb9657ab3f9 Author: Pxl <952130...@qq.com> AuthorDate: Sun Apr 24 12:09:40 2022 +0800 [Feature] [Lateral-View] support outer combinator of table function (#9147) --- be/src/exprs/table_function/table_function.h | 13 ++- .../table_function/table_function_factory.cpp | 50 ++++----- .../exprs/table_function/table_function_factory.h | 12 +- be/src/vec/exprs/table_function/vexplode.cpp | 9 +- be/src/vec/exprs/table_function/vexplode.h | 4 +- be/src/vec/functions/function_fake.cpp | 54 +++++++-- be/src/vec/functions/function_fake.h | 70 +----------- be/src/vec/functions/simple_function_factory.h | 13 ++- be/test/vec/function/table_function_test.cpp | 13 +-- docs/.vuepress/sidebar/en.js | 3 +- docs/.vuepress/sidebar/zh-CN.js | 3 +- .../table-functions/outer-combinator.md | 48 ++++++++ .../table-functions/explode-bitmap.md | 11 +- .../table-functions/explode-json-array.md | 121 ++------------------- .../sql-functions/table-functions/explode-split.md | 8 +- .../table-functions/outer-combinator.md | 48 ++++++++ .../java/org/apache/doris/catalog/FunctionSet.java | 104 ++++++++---------- 17 files changed, 269 insertions(+), 315 deletions(-) diff --git a/be/src/exprs/table_function/table_function.h b/be/src/exprs/table_function/table_function.h index 3c2e188950..901572996b 100644 --- a/be/src/exprs/table_function/table_function.h +++ b/be/src/exprs/table_function/table_function.h @@ -30,6 +30,8 @@ namespace doris { // Currently, the memory allocated from table function is from malloc directly. class TableFunctionState {}; +constexpr auto COMBINATOR_SUFFIX_OUTER = "_outer"; + class ExprContext; class TupleRow; class TableFunction { @@ -99,6 +101,14 @@ public: } bool is_outer() const { return _is_outer; } + void set_outer() { + if (is_outer()) { + return; + } + _is_outer = true; + _fn_name += COMBINATOR_SUFFIX_OUTER; + } + bool current_empty() const { return _is_current_empty; } protected: @@ -115,7 +125,6 @@ protected: // the size of current result int64_t _cur_size = 0; // set _is_outer to false for explode function, and should not return tuple while array is null or empty - bool _is_outer = true; + bool _is_outer = false; }; - } // namespace doris diff --git a/be/src/exprs/table_function/table_function_factory.cpp b/be/src/exprs/table_function/table_function_factory.cpp index e44e3e65ed..2415627ccd 100644 --- a/be/src/exprs/table_function/table_function_factory.cpp +++ b/be/src/exprs/table_function/table_function_factory.cpp @@ -17,17 +17,6 @@ #include "exprs/table_function/table_function_factory.h" -#include "common/object_pool.h" -#include "exprs/table_function/explode_bitmap.h" -#include "exprs/table_function/explode_json_array.h" -#include "exprs/table_function/explode_split.h" -#include "exprs/table_function/table_function.h" -#include "vec/exprs/table_function/vexplode.h" -#include "vec/exprs/table_function/vexplode_bitmap.h" -#include "vec/exprs/table_function/vexplode_json_array.h" -#include "vec/exprs/table_function/vexplode_numbers.h" -#include "vec/exprs/table_function/vexplode_split.h" - namespace doris { template <typename TableFunctionType> @@ -49,12 +38,6 @@ struct TableFunctionCreator<vectorized::VExplodeJsonArrayTableFunction> { } }; -template <> -struct TableFunctionCreator<vectorized::VExplodeTableFunction> { - bool is_outer; - TableFunction* operator()() { return new vectorized::VExplodeTableFunction(is_outer); } -}; - inline auto ExplodeJsonArrayIntCreator = TableFunctionCreator<ExplodeJsonArrayTableFunction> {ExplodeJsonArrayType::INT}; inline auto ExplodeJsonArrayDoubleCreator = @@ -72,10 +55,7 @@ inline auto VExplodeJsonArrayStringCreator = TableFunctionCreator<vectorized::VExplodeJsonArrayTableFunction> { ExplodeJsonArrayType::STRING}; -inline auto VExplodeCreator = TableFunctionCreator<vectorized::VExplodeTableFunction> {false}; -inline auto VExplodeOuterCreator = TableFunctionCreator<vectorized::VExplodeTableFunction> {true}; - -//{fn_name,is_vectorized}->table_function_creator +// {fn_name, is_vectorized} -> table_function_creator const std::unordered_map<std::pair<std::string, bool>, std::function<TableFunction*()>> TableFunctionFactory::_function_map { {{"explode_split", false}, TableFunctionCreator<ExplodeSplitTableFunction> {}}, @@ -92,19 +72,37 @@ const std::unordered_map<std::pair<std::string, bool>, std::function<TableFuncti {{"explode_json_array_string", true}, VExplodeJsonArrayStringCreator}, {{"explode_bitmap", true}, TableFunctionCreator<vectorized::VExplodeBitmapTableFunction>()}, - {{"explode", true}, VExplodeCreator}, - {{"explode_outer", true}, VExplodeOuterCreator}}; // namespace doris + {{"explode", true}, TableFunctionCreator<vectorized::VExplodeTableFunction> {}}}; -Status TableFunctionFactory::get_fn(const std::string& fn_name, bool is_vectorized, +Status TableFunctionFactory::get_fn(const std::string& fn_name_raw, bool is_vectorized, ObjectPool* pool, TableFunction** fn) { - auto fn_iterator = _function_map.find({fn_name, is_vectorized}); + auto match_suffix = [](const std::string& name, const std::string& suffix) -> bool { + if (name.length() < suffix.length()) { + return false; + } + return name.substr(name.length() - suffix.length()) == suffix; + }; + + auto remove_suffix = [](const std::string& name, const std::string& suffix) -> std::string { + return name.substr(0, name.length() - suffix.length()); + }; + + bool is_outer = match_suffix(fn_name_raw, COMBINATOR_SUFFIX_OUTER); + std::string fn_name_real = + is_outer ? remove_suffix(fn_name_raw, COMBINATOR_SUFFIX_OUTER) : fn_name_raw; + + auto fn_iterator = _function_map.find({fn_name_real, is_vectorized}); if (fn_iterator != _function_map.end()) { *fn = pool->add(fn_iterator->second()); + if (is_outer) { + (*fn)->set_outer(); + } + return Status::OK(); } return Status::NotSupported(std::string(is_vectorized ? "vectorized " : "") + - "table function " + fn_name + " not support"); + "table function " + fn_name_raw + " not support"); } } // namespace doris diff --git a/be/src/exprs/table_function/table_function_factory.h b/be/src/exprs/table_function/table_function_factory.h index eaa1b86c63..05d4fa2e74 100644 --- a/be/src/exprs/table_function/table_function_factory.h +++ b/be/src/exprs/table_function/table_function_factory.h @@ -20,9 +20,17 @@ #include <functional> #include <unordered_map> +#include "common/object_pool.h" #include "common/status.h" +#include "exprs/table_function/explode_bitmap.h" +#include "exprs/table_function/explode_json_array.h" #include "exprs/table_function/explode_split.h" -#include "exprs/table_function/table_function_factory.h" +#include "exprs/table_function/table_function.h" +#include "vec/exprs/table_function/vexplode.h" +#include "vec/exprs/table_function/vexplode_bitmap.h" +#include "vec/exprs/table_function/vexplode_json_array.h" +#include "vec/exprs/table_function/vexplode_numbers.h" +#include "vec/exprs/table_function/vexplode_split.h" namespace doris { @@ -32,7 +40,7 @@ class TableFunctionFactory { public: TableFunctionFactory() {} ~TableFunctionFactory() {} - static Status get_fn(const std::string& fn_name, bool is_vectorized, ObjectPool* pool, + static Status get_fn(const std::string& fn_name_raw, bool is_vectorized, ObjectPool* pool, TableFunction** fn); const static std::unordered_map<std::pair<std::string, bool>, std::function<TableFunction*()>> diff --git a/be/src/vec/exprs/table_function/vexplode.cpp b/be/src/vec/exprs/table_function/vexplode.cpp index 58f8e7f2e0..adb0db076d 100644 --- a/be/src/vec/exprs/table_function/vexplode.cpp +++ b/be/src/vec/exprs/table_function/vexplode.cpp @@ -21,13 +21,8 @@ namespace doris::vectorized { -VExplodeTableFunction::VExplodeTableFunction(bool is_outer) { - _is_outer = is_outer; - if (_is_outer) { - _fn_name = "vexplode_outer"; - } else { - _fn_name = "vexplode"; - } +VExplodeTableFunction::VExplodeTableFunction() { + _fn_name = "vexplode"; } Status VExplodeTableFunction::process_init(vectorized::Block* block) { diff --git a/be/src/vec/exprs/table_function/vexplode.h b/be/src/vec/exprs/table_function/vexplode.h index b7ee993c0e..da4909994b 100644 --- a/be/src/vec/exprs/table_function/vexplode.h +++ b/be/src/vec/exprs/table_function/vexplode.h @@ -18,16 +18,16 @@ #pragma once #include "exprs/table_function/table_function.h" -#include "vec/common/string_ref.h" #include "vec/columns/column.h" #include "vec/columns/column_array.h" #include "vec/columns/column_nullable.h" +#include "vec/common/string_ref.h" namespace doris::vectorized { class VExplodeTableFunction : public TableFunction { public: - VExplodeTableFunction(bool is_outer); + VExplodeTableFunction(); virtual ~VExplodeTableFunction() = default; diff --git a/be/src/vec/functions/function_fake.cpp b/be/src/vec/functions/function_fake.cpp index b661960517..1f52297806 100644 --- a/be/src/vec/functions/function_fake.cpp +++ b/be/src/vec/functions/function_fake.cpp @@ -17,18 +17,54 @@ #include "vec/functions/function_fake.h" +#include <boost/metaparse/string.hpp> +#include <string_view> +#include <type_traits> + namespace doris::vectorized { +// We can use std::basic_fixed_string with c++20 in the future +template <const char* Name, typename ReturnType> +struct FakeFunctionBaseImpl { + static constexpr auto name = Name; + static DataTypePtr get_return_type_impl(const DataTypes& arguments) { + return std::make_shared<ReturnType>(); + } +}; + +#define C_STR(str_) boost::mpl::c_str<BOOST_METAPARSE_STRING(str_)>::value + +using FunctionEsquery = FakeFunctionBaseImpl<C_STR("esquery"), DataTypeUInt8>; + +using FunctionExplodeSplit = FakeFunctionBaseImpl<C_STR("explode_split"), DataTypeString>; +using FunctionExplodeNumbers = FakeFunctionBaseImpl<C_STR("explode_numbers"), DataTypeInt32>; +using FunctionExplodeJsonArrayInt = + FakeFunctionBaseImpl<C_STR("explode_json_array_int"), DataTypeInt64>; +using FunctionExplodeJsonArrayString = + FakeFunctionBaseImpl<C_STR("explode_json_array_string"), DataTypeString>; +using FunctionExplodeJsonArrayDouble = + FakeFunctionBaseImpl<C_STR("explode_json_array_double"), DataTypeFloat64>; +using FunctionExplodeBitmap = FakeFunctionBaseImpl<C_STR("explode_bitmap"), DataTypeInt64>; + +struct FunctionExplode { + static constexpr auto name = "explode"; + static DataTypePtr get_return_type_impl(const DataTypes& arguments) { + DCHECK(is_array(arguments[0])) << arguments[0]->get_name() << " not supported"; + return make_nullable( + check_and_get_data_type<DataTypeArray>(arguments[0].get())->get_nested_type()); + } +}; + void register_function_fake(SimpleFunctionFactory& factory) { - factory.register_function<FunctionFake<FunctionEsqueryImpl>>(); - factory.register_function<FunctionFake<FunctionExplodeSplitImpl>>(); - factory.register_function<FunctionFake<FunctionExplodeNumbersImpl>>(); - factory.register_function<FunctionFake<FunctionExplodeJsonArrayDoubleImpl>>(); - factory.register_function<FunctionFake<FunctionExplodeJsonArrayIntImpl>>(); - factory.register_function<FunctionFake<FunctionExplodeJsonArrayStringImpl>>(); - factory.register_function<FunctionFake<FunctionExplodeBitmapImpl>>(); - factory.register_function<FunctionFake<FunctionExplodeImpl>>(); - factory.register_function<FunctionFake<FunctionExplodeOuterImpl>>(); + factory.register_function<FunctionFake<FunctionEsquery>>(); + + factory.register_table_function<FunctionFake<FunctionExplodeSplit>>(); + factory.register_table_function<FunctionFake<FunctionExplodeNumbers>>(); + factory.register_table_function<FunctionFake<FunctionExplodeJsonArrayDouble>>(); + factory.register_table_function<FunctionFake<FunctionExplodeJsonArrayInt>>(); + factory.register_table_function<FunctionFake<FunctionExplodeJsonArrayString>>(); + factory.register_table_function<FunctionFake<FunctionExplodeBitmap>>(); + factory.register_table_function<FunctionFake<FunctionExplode>>(); } } // namespace doris::vectorized diff --git a/be/src/vec/functions/function_fake.h b/be/src/vec/functions/function_fake.h index 56648d8877..eaaecaf843 100644 --- a/be/src/vec/functions/function_fake.h +++ b/be/src/vec/functions/function_fake.h @@ -27,75 +27,7 @@ #include "vec/utils/util.hpp" namespace doris::vectorized { - -struct FunctionEsqueryImpl { - static constexpr auto name = "esquery"; - static DataTypePtr get_return_type_impl(const DataTypes& arguments) { - return std::make_shared<DataTypeUInt8>(); - } -}; - -struct FunctionExplodeSplitImpl { - static constexpr auto name = "explode_split"; - static DataTypePtr get_return_type_impl(const DataTypes& arguments) { - return std::make_shared<DataTypeString>(); - } -}; - -struct FunctionExplodeNumbersImpl { - static constexpr auto name = "explode_numbers"; - static DataTypePtr get_return_type_impl(const DataTypes& arguments) { - return std::make_shared<DataTypeInt32>(); - } -}; - -struct FunctionExplodeJsonArrayIntImpl { - static constexpr auto name = "explode_json_array_int"; - static DataTypePtr get_return_type_impl(const DataTypes& arguments) { - return std::make_shared<DataTypeInt64>(); - } -}; - -struct FunctionExplodeJsonArrayStringImpl { - static constexpr auto name = "explode_json_array_string"; - static DataTypePtr get_return_type_impl(const DataTypes& arguments) { - return std::make_shared<DataTypeString>(); - } -}; - -struct FunctionExplodeJsonArrayDoubleImpl { - static constexpr auto name = "explode_json_array_double"; - static DataTypePtr get_return_type_impl(const DataTypes& arguments) { - return std::make_shared<DataTypeFloat64>(); - } -}; - -struct FunctionExplodeBitmapImpl { - static constexpr auto name = "explode_bitmap"; - static DataTypePtr get_return_type_impl(const DataTypes& arguments) { - return std::make_shared<DataTypeInt64>(); - } -}; - -struct FunctionExplodeImpl { - static constexpr auto name = "explode"; - static DataTypePtr get_return_type_impl(const DataTypes& arguments) { - DCHECK(is_array(arguments[0])) << arguments[0]->get_name() << " not supported"; - return make_nullable( - check_and_get_data_type<DataTypeArray>(arguments[0].get())->get_nested_type()); - } -}; - -struct FunctionExplodeOuterImpl { - static constexpr auto name = "explode_outer"; - static DataTypePtr get_return_type_impl(const DataTypes& arguments) { - DCHECK(is_array(arguments[0])) << arguments[0]->get_name() << " not supported"; - return make_nullable( - check_and_get_data_type<DataTypeArray>(arguments[0].get())->get_nested_type()); - } -}; - -//FunctionFake is use for some function call expr only work at prepare/open phase, do not support execute(). +// FunctionFake is use for some function call expr only work at prepare/open phase, do not support execute(). template <typename Impl> class FunctionFake : public IFunction { public: diff --git a/be/src/vec/functions/simple_function_factory.h b/be/src/vec/functions/simple_function_factory.h index 48266e303b..033682212a 100644 --- a/be/src/vec/functions/simple_function_factory.h +++ b/be/src/vec/functions/simple_function_factory.h @@ -23,6 +23,7 @@ #include <mutex> #include <string> +#include "exprs/table_function/table_function.h" #include "vec/functions/function.h" namespace doris::vectorized { @@ -103,10 +104,18 @@ public: template <class Function> void register_function() { - if constexpr (std::is_base_of<IFunction, Function>::value) + if constexpr (std::is_base_of<IFunction, Function>::value) { register_function(Function::name, &createDefaultFunction<Function>); - else + } else { register_function(Function::name, &Function::create); + } + } + + template <class Function> + void register_table_function() { + function_creators[Function::name] = &createDefaultFunction<Function>; + function_creators[std::string(Function::name) + COMBINATOR_SUFFIX_OUTER] = + &createDefaultFunction<Function>; } void register_alias(const std::string& name, const std::string& alias) { diff --git a/be/test/vec/function/table_function_test.cpp b/be/test/vec/function/table_function_test.cpp index f525138d65..19e53dc8a4 100644 --- a/be/test/vec/function/table_function_test.cpp +++ b/be/test/vec/function/table_function_test.cpp @@ -64,7 +64,8 @@ private: TEST_F(TableFunctionTest, vexplode_outer) { init_expr_context(1); - VExplodeTableFunction explode_outer(true); + VExplodeTableFunction explode_outer; + explode_outer.set_outer(); explode_outer.set_vexpr_context(_ctx.get()); // explode_outer(Array<Int32>) @@ -95,7 +96,7 @@ TEST_F(TableFunctionTest, vexplode_outer) { TEST_F(TableFunctionTest, vexplode) { init_expr_context(1); - VExplodeTableFunction explode(false); + VExplodeTableFunction explode; explode.set_vexpr_context(_ctx.get()); // explode(Array<Int32>) @@ -134,8 +135,7 @@ TEST_F(TableFunctionTest, vexplode_numbers) { InputDataSet input_set = {{Int32(2)}, {Int32(3)}, {Null()}, {Int32(0)}, {Int32(-2)}}; InputTypeSet output_types = {TypeIndex::Int32}; - InputDataSet output_set = {{Int32(0)}, {Int32(1)}, {Int32(0)}, {Int32(1)}, - {Int32(2)}, {Null()}, {Null()}, {Null()}}; + InputDataSet output_set = {{Int32(0)}, {Int32(1)}, {Int32(0)}, {Int32(1)}, {Int32(2)}}; check_vec_table_function(&tfn, input_types, input_set, output_types, output_set); } @@ -158,9 +158,8 @@ TEST_F(TableFunctionTest, vexplode_split) { {std::string(""), std::string(",")}}; InputTypeSet output_types = {TypeIndex::String}; - InputDataSet output_set = {{Null()}, {std::string("a")}, {std::string("b")}, - {std::string("c")}, {std::string("")}, {std::string("b,c")}, - {std::string("")}}; + InputDataSet output_set = {{std::string("a")}, {std::string("b")}, {std::string("c")}, + {std::string("")}, {std::string("b,c")}, {std::string("")}}; check_vec_table_function(&tfn, input_types, input_set, output_types, output_set); } diff --git a/docs/.vuepress/sidebar/en.js b/docs/.vuepress/sidebar/en.js index e28083d851..6a3d7ffda3 100644 --- a/docs/.vuepress/sidebar/en.js +++ b/docs/.vuepress/sidebar/en.js @@ -544,7 +544,8 @@ module.exports = [ "explode-bitmap", "explode-split", "explode-json-array", - "explode-numbers" + "explode-numbers", + "outer-combinator" ], }, "window-function", diff --git a/docs/.vuepress/sidebar/zh-CN.js b/docs/.vuepress/sidebar/zh-CN.js index 83e7f22f9b..13ef8c0daf 100644 --- a/docs/.vuepress/sidebar/zh-CN.js +++ b/docs/.vuepress/sidebar/zh-CN.js @@ -558,7 +558,8 @@ module.exports = [ "explode-bitmap", "explode-split", "explode-json-array", - "explode-numbers" + "explode-numbers", + "outer-combinator" ], }, "window-function", diff --git a/docs/en/sql-reference/sql-functions/table-functions/outer-combinator.md b/docs/en/sql-reference/sql-functions/table-functions/outer-combinator.md new file mode 100644 index 0000000000..83bed087d9 --- /dev/null +++ b/docs/en/sql-reference/sql-functions/table-functions/outer-combinator.md @@ -0,0 +1,48 @@ +--- +{ + "title": "outer combinator", + "language": "en" +} +--- + +<!-- +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. +--> + +# outer combinator + +## description + +Adding the `_outer` suffix after the function name of the table function changes the function behavior from `non-outer` to `outer`, and adds a row of `Null` data when the table function generates 0 rows of data. + +## example + +``` +mysql> select e1 from (select 1 k1) as t lateral view explode_numbers(0) tmp1 as e1; +Empty set + +mysql> select e1 from (select 1 k1) as t lateral view explode_numbers_outer(0) tmp1 as e1; ++------+ +| e1 | ++------+ +| NULL | ++------+ +``` +## keyword + + outer \ No newline at end of file diff --git a/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-bitmap.md b/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-bitmap.md index 99f79711ac..e6302f46f3 100644 --- a/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-bitmap.md +++ b/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-bitmap.md @@ -60,16 +60,7 @@ Lateral View: ``` mysql> select k1, e1 from example1 lateral view explode_bitmap(bitmap_empty()) tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 2 | NULL | -| 3 | NULL | -| 4 | NULL | -| 5 | NULL | -| 6 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_bitmap(bitmap_from_string("1")) tmp1 as e1 order by k1, e1; +------+------+ diff --git a/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-json-array.md b/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-json-array.md index 8332d6a8e4..d5a08f8140 100644 --- a/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-json-array.md +++ b/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-json-array.md @@ -62,13 +62,7 @@ Lateral View: ``` mysql> select k1, e1 from example1 lateral view explode_json_array_int('[]') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 2 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_int('[1,2,3]') tmp1 as e1 order by k1, e1; +------+------+ @@ -89,79 +83,28 @@ mysql> select k1, e1 from example1 lateral view explode_json_array_int('[1,"b",3 +------+------+ | k1 | e1 | +------+------+ -| 1 | NULL | | 1 | 1 | | 1 | 3 | -| 2 | NULL | | 2 | 1 | | 2 | 3 | -| 3 | NULL | | 3 | 1 | | 3 | 3 | +------+------+ mysql> select k1, e1 from example1 lateral view explode_json_array_int('["a","b","c"]') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 1 | NULL | -| 1 | NULL | -| 2 | NULL | -| 2 | NULL | -| 2 | NULL | -| 3 | NULL | -| 3 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_int('{"a": 3}') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 2 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_double('[]') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 2 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_double('[1,2,3]') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 1 | NULL | -| 1 | NULL | -| 2 | NULL | -| 2 | NULL | -| 2 | NULL | -| 3 | NULL | -| 3 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_double('[1,"b",3]') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 1 | NULL | -| 1 | NULL | -| 2 | NULL | -| 2 | NULL | -| 2 | NULL | -| 3 | NULL | -| 3 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_double('[1.0,2.0,3.0]') tmp1 as e1 order by k1, e1; +------+------+ @@ -179,52 +122,16 @@ mysql> select k1, e1 from example1 lateral view explode_json_array_double('[1.0, +------+------+ mysql> select k1, e1 from example1 lateral view explode_json_array_double('[1,"b",3]') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 1 | NULL | -| 1 | NULL | -| 2 | NULL | -| 2 | NULL | -| 2 | NULL | -| 3 | NULL | -| 3 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_double('["a","b","c"]') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 1 | NULL | -| 1 | NULL | -| 2 | NULL | -| 2 | NULL | -| 2 | NULL | -| 3 | NULL | -| 3 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_double('{"a": 3}') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 2 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_string('[]') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 2 | NULL | -| 3 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_json_array_string('[1.0,2.0,3.0]') tmp1 as e1 order by k1, e1; +------+----------+ @@ -272,13 +179,7 @@ mysql> select k1, e1 from example1 lateral view explode_json_array_string('["a", +------+------+ mysql> select k1, e1 from example1 lateral view explode_json_array_string('{"a": 3}') tmp1 as e1 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 1 | NULL | -| 2 | NULL | -| 3 | NULL | -+------+------+ +Empty set ``` ## keyword diff --git a/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-split.md b/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-split.md index d7c403186e..6bc0ea3fe7 100644 --- a/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-split.md +++ b/docs/zh-CN/sql-reference/sql-functions/table-functions/explode-split.md @@ -67,11 +67,7 @@ mysql> select k1, e1 from example1 lateral view explode_split(k2, ',') tmp1 as e +------+------+ mysql> select k1, e1 from example1 lateral view explode_split(k2, ',') tmp1 as e1 where k1 = 2 order by k1, e1; -+------+------+ -| k1 | e1 | -+------+------+ -| 2 | NULL | -+------+------+ +Empty set mysql> select k1, e1 from example1 lateral view explode_split(k2, ',') tmp1 as e1 where k1 = 3 order by k1, e1; +------+------+ @@ -103,7 +99,7 @@ mysql> select k1, e1 from example1 lateral view explode_split(k2, ',') tmp1 as e +------+------+ | 6 | b | | 6 | c | -| 6 | a | +| 6 | a | +------+------+ ``` diff --git a/docs/zh-CN/sql-reference/sql-functions/table-functions/outer-combinator.md b/docs/zh-CN/sql-reference/sql-functions/table-functions/outer-combinator.md new file mode 100644 index 0000000000..ef9f97047e --- /dev/null +++ b/docs/zh-CN/sql-reference/sql-functions/table-functions/outer-combinator.md @@ -0,0 +1,48 @@ +--- +{ + "title": "outer组合器", + "language": "zh-CN" +} +--- + +<!-- +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. +--> + +# outer组合器 + +## description + +在table function的函数名后面添加`_outer`后缀使得函数行为从`non-outer`变为`outer`,在表函数生成0行数据时添加一行`Null`数据。 + +## example + +``` +mysql> select e1 from (select 1 k1) as t lateral view explode_numbers(0) tmp1 as e1; +Empty set + +mysql> select e1 from (select 1 k1) as t lateral view explode_numbers_outer(0) tmp1 as e1; ++------+ +| e1 | ++------+ +| NULL | ++------+ +``` +## keyword + + outer \ No newline at end of file diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java index e95b1c66bb..b6c08cba93 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java @@ -25,6 +25,7 @@ import org.apache.doris.analysis.InPredicate; import org.apache.doris.analysis.IsNullPredicate; import org.apache.doris.analysis.LikePredicate; import org.apache.doris.builtins.ScalarBuiltins; +import org.apache.doris.catalog.Function.NullableMode; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; @@ -2482,81 +2483,62 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo public static final String EXPLODE_JSON_ARRAY_STRING = "explode_json_array_string"; public static final String EXPLODE_NUMBERS = "explode_numbers"; public static final String EXPLODE = "explode"; - public static final String EXPLODE_OUTER = "explode_outer"; + + private void addTableFunction(String name, Type retType, NullableMode nullableMode, ArrayList<Type> argTypes, + boolean hasVarArgs, String symbol) { + List<Function> functionList = tableFunctions.get(name); + functionList.add(ScalarFunction.createBuiltin(name, retType, nullableMode, argTypes, hasVarArgs, symbol, null, + null, true)); + } + + private void addTableFunctionWithCombinator(String name, Type retType, NullableMode nullableMode, + ArrayList<Type> argTypes, boolean hasVarArgs, String symbol) { + addTableFunction(name, retType, nullableMode, argTypes, hasVarArgs, symbol); + addTableFunction(name + "_outer", retType, Function.NullableMode.ALWAYS_NULLABLE, argTypes, hasVarArgs, symbol); + } + + private void initTableFunctionListWithCombinator(String name) { + tableFunctions.put(name, Lists.newArrayList()); + tableFunctions.put(name + "_outer", Lists.newArrayList()); + } private void initTableFunction() { - List<Function> explodeSplits = Lists.newArrayList(); - explodeSplits.add(ScalarFunction.createBuiltin( - EXPLODE_SPLIT, Type.VARCHAR, Function.NullableMode.DEPEND_ON_ARGUMENT, + initTableFunctionListWithCombinator(EXPLODE_SPLIT); + addTableFunctionWithCombinator(EXPLODE_SPLIT, Type.VARCHAR, Function.NullableMode.DEPEND_ON_ARGUMENT, Lists.newArrayList(Type.VARCHAR, Type.VARCHAR), false, - "_ZN5doris19DummyTableFunctions13explode_splitEPN9doris_udf15FunctionContextERKNS1_9StringValES6_", - null, null, true)); - tableFunctions.put(EXPLODE_SPLIT, explodeSplits); + "_ZN5doris19DummyTableFunctions13explode_splitEPN9doris_udf15FunctionContextERKNS1_9StringValES6_"); - List<Function> explodeBitmaps = Lists.newArrayList(); - explodeBitmaps.add(ScalarFunction.createBuiltin( - EXPLODE_BITMAP, Type.BIGINT, Function.NullableMode.DEPEND_ON_ARGUMENT, + initTableFunctionListWithCombinator(EXPLODE_BITMAP); + addTableFunctionWithCombinator(EXPLODE_BITMAP, Type.BIGINT, Function.NullableMode.DEPEND_ON_ARGUMENT, Lists.newArrayList(Type.BITMAP), false, - "_ZN5doris19DummyTableFunctions14explode_bitmapEPN9doris_udf15FunctionContextERKNS1_9StringValE", - null, null, true)); - tableFunctions.put(EXPLODE_BITMAP, explodeBitmaps); + "_ZN5doris19DummyTableFunctions14explode_bitmapEPN9doris_udf15FunctionContextERKNS1_9StringValE"); - List<Function> explodeJsonArrayInts = Lists.newArrayList(); - explodeJsonArrayInts.add(ScalarFunction.createBuiltin( - EXPLODE_JSON_ARRAY_INT, Type.BIGINT, Function.NullableMode.DEPEND_ON_ARGUMENT, + initTableFunctionListWithCombinator(EXPLODE_JSON_ARRAY_INT); + addTableFunctionWithCombinator(EXPLODE_JSON_ARRAY_INT, Type.BIGINT, Function.NullableMode.DEPEND_ON_ARGUMENT, Lists.newArrayList(Type.VARCHAR), false, - "_ZN5doris19DummyTableFunctions22explode_json_array_intEPN9doris_udf15FunctionContextERKNS1_9StringValE", - null, null, true)); - tableFunctions.put(EXPLODE_JSON_ARRAY_INT, explodeJsonArrayInts); + "_ZN5doris19DummyTableFunctions22explode_json_array_intEPN9doris_udf15FunctionContextERKNS1_9StringValE"); - List<Function> explodeJsonArrayDoubles = Lists.newArrayList(); - explodeJsonArrayDoubles.add(ScalarFunction.createBuiltin( - EXPLODE_JSON_ARRAY_DOUBLE, Type.DOUBLE, Function.NullableMode.DEPEND_ON_ARGUMENT, + initTableFunctionListWithCombinator(EXPLODE_JSON_ARRAY_DOUBLE); + addTableFunctionWithCombinator(EXPLODE_JSON_ARRAY_DOUBLE, Type.DOUBLE, Function.NullableMode.DEPEND_ON_ARGUMENT, Lists.newArrayList(Type.VARCHAR), false, - "_ZN5doris19DummyTableFunctions25explode_json_array_doubleEPN9doris_udf15FunctionContextERKNS1_9StringValE", - null, null, true)); - tableFunctions.put(EXPLODE_JSON_ARRAY_DOUBLE, explodeJsonArrayDoubles); + "_ZN5doris19DummyTableFunctions25explode_json_array_doubleEPN9doris_udf15FunctionContextERKNS1_9StringValE"); - List<Function> explodeJsonArrayStrings = Lists.newArrayList(); - explodeJsonArrayStrings.add(ScalarFunction.createBuiltin( - EXPLODE_JSON_ARRAY_STRING, Type.VARCHAR, Function.NullableMode.DEPEND_ON_ARGUMENT, - Lists.newArrayList(Type.VARCHAR), false, - "_ZN5doris19DummyTableFunctions25explode_json_array_stringEPN9doris_udf15FunctionContextERKNS1_9StringValE", - null, null, true)); - tableFunctions.put(EXPLODE_JSON_ARRAY_STRING, explodeJsonArrayStrings); + initTableFunctionListWithCombinator(EXPLODE_JSON_ARRAY_STRING); + addTableFunctionWithCombinator(EXPLODE_JSON_ARRAY_STRING, Type.VARCHAR, + Function.NullableMode.DEPEND_ON_ARGUMENT, Lists.newArrayList(Type.VARCHAR), false, + "_ZN5doris19DummyTableFunctions25explode_json_array_stringEPN9doris_udf15FunctionContextERKNS1_9StringValE"); - List<Function> explodeNumbers = Lists.newArrayList(); - explodeNumbers.add(ScalarFunction.createBuiltin( - EXPLODE_NUMBERS, Type.INT, Function.NullableMode.DEPEND_ON_ARGUMENT, + initTableFunctionListWithCombinator(EXPLODE_NUMBERS); + addTableFunctionWithCombinator(EXPLODE_NUMBERS, Type.INT, Function.NullableMode.DEPEND_ON_ARGUMENT, Lists.newArrayList(Type.INT), false, - "_ZN5doris19DummyTableFunctions22explode_numbersEPN9doris_udf15FunctionContextERKNS1_9IntValE", - null, null, true)); - tableFunctions.put(EXPLODE_NUMBERS, explodeNumbers); - - List<Function> explodes = Lists.newArrayList(); - explodes.add(ScalarFunction.createBuiltin( - EXPLODE, Type.INT, Function.NullableMode.ALWAYS_NULLABLE, - Lists.newArrayList(new ArrayType(Type.INT)), false, - "_ZN5doris19DummyTableFunctions7explodeEPN9doris_udf15FunctionContextERKNS1_13CollectionValE", - null, null, true)); - explodes.add(ScalarFunction.createBuiltin( - EXPLODE, Type.VARCHAR, Function.NullableMode.ALWAYS_NULLABLE, - Lists.newArrayList(new ArrayType(Type.VARCHAR)), false, - "_ZN5doris19DummyTableFunctions7explodeEPN9doris_udf15FunctionContextERKNS1_13CollectionValE", - null, null, true)); - tableFunctions.put(EXPLODE, explodes); + "_ZN5doris19DummyTableFunctions22explode_numbersEPN9doris_udf15FunctionContextERKNS1_9IntValE"); - List<Function> explodeOuters = Lists.newArrayList(); - explodeOuters.add(ScalarFunction.createBuiltin( - EXPLODE_OUTER, Type.INT, Function.NullableMode.ALWAYS_NULLABLE, + initTableFunctionListWithCombinator(EXPLODE); + addTableFunctionWithCombinator(EXPLODE, Type.INT, Function.NullableMode.ALWAYS_NULLABLE, Lists.newArrayList(new ArrayType(Type.INT)), false, - "_ZN5doris19DummyTableFunctions13explode_outerEPN9doris_udf15FunctionContextERKNS1_13CollectionValE", - null, null, true)); - explodeOuters.add(ScalarFunction.createBuiltin( - EXPLODE_OUTER, Type.VARCHAR, Function.NullableMode.ALWAYS_NULLABLE, + "_ZN5doris19DummyTableFunctions7explodeEPN9doris_udf15FunctionContextERKNS1_13CollectionValE"); + addTableFunctionWithCombinator(EXPLODE, Type.VARCHAR, Function.NullableMode.ALWAYS_NULLABLE, Lists.newArrayList(new ArrayType(Type.VARCHAR)), false, - "_ZN5doris19DummyTableFunctions13explode_outerEPN9doris_udf15FunctionContextERKNS1_13CollectionValE", - null, null, true)); - tableFunctions.put(EXPLODE_OUTER, explodeOuters); + "_ZN5doris19DummyTableFunctions7explodeEPN9doris_udf15FunctionContextERKNS1_13CollectionValE"); } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org