diff --git a/be/src/exec/table_function_node.cpp b/be/src/exec/table_function_node.cpp index 01a023b07b..50351438c3 100644 --- a/be/src/exec/table_function_node.cpp +++ b/be/src/exec/table_function_node.cpp @@ -78,6 +78,16 @@ Status TableFunctionNode::_prepare_output_slot_ids(const TPlanNode& tnode) { return Status::OK(); } +bool TableFunctionNode::_is_inner_and_empty() { + for (int i = 0; i < _fn_num; i++) { + // if any table function is not outer and has empty result, go to next child row + if (!_fns[i]->is_outer() && _fns[i]->current_empty()) { + return true; + } + } + return false; +} + Status TableFunctionNode::prepare(RuntimeState* state) { RETURN_IF_ERROR(ExecNode::prepare(state)); SCOPED_SWITCH_TASK_THREAD_LOCAL_MEM_TRACKER(mem_tracker()); @@ -230,9 +240,10 @@ Status TableFunctionNode::get_next(RuntimeState* state, RowBatch* row_batch, boo } } + bool skip_child_row = false; while (true) { int idx = _find_last_fn_eos_idx(); - if (idx == 0) { + if (idx == 0 || skip_child_row) { // all table functions' results are exhausted, process next child row RETURN_IF_ERROR(_process_next_child_row()); if (_child_batch_exhausted) { @@ -246,6 +257,11 @@ Status TableFunctionNode::get_next(RuntimeState* state, RowBatch* row_batch, boo } } + // if any table function is not outer and has empty result, go to next child row + if (skip_child_row = _is_inner_and_empty(); skip_child_row) { + continue; + } + // get slots from every table function // Notice that _fn_values[i] may be null if the table function has empty result set. for (int i = 0; i < _fn_num; i++) { diff --git a/be/src/exec/table_function_node.h b/be/src/exec/table_function_node.h index fd06760943..06de804c3c 100644 --- a/be/src/exec/table_function_node.h +++ b/be/src/exec/table_function_node.h @@ -32,14 +32,15 @@ public: TableFunctionNode(ObjectPool* pool, const TPlanNode& tnode, const DescriptorTbl& descs); ~TableFunctionNode(); - virtual Status init(const TPlanNode& tnode, RuntimeState* state = nullptr); - virtual Status prepare(RuntimeState* state); - virtual Status open(RuntimeState* state); - virtual Status get_next(RuntimeState* state, RowBatch* row_batch, bool* eos); - virtual Status close(RuntimeState* state); + Status init(const TPlanNode& tnode, RuntimeState* state = nullptr) override; + Status prepare(RuntimeState* state) override; + Status open(RuntimeState* state) override; + Status get_next(RuntimeState* state, RowBatch* row_batch, bool* eos) override; + Status close(RuntimeState* state) override; protected: Status _prepare_output_slot_ids(const TPlanNode& tnode); + bool _is_inner_and_empty(); // return: // 0: all fns are eos diff --git a/be/src/vec/exec/vtable_function_node.cpp b/be/src/vec/exec/vtable_function_node.cpp index 6b25849f77..d21b252f35 100644 --- a/be/src/vec/exec/vtable_function_node.cpp +++ b/be/src/vec/exec/vtable_function_node.cpp @@ -92,16 +92,6 @@ Status VTableFunctionNode::get_next(RuntimeState* state, Block* block, bool* eos return Status::OK(); } -bool VTableFunctionNode::_is_inner_and_empty() { - for (int i = 0; i < _fn_num; i++) { - // if any table function is not outer and has empty result, go to next child row - if (!_fns[i]->is_outer() && _fns[i]->current_empty()) { - return true; - } - } - return false; -} - Status VTableFunctionNode::get_expanded_block(RuntimeState* state, Block* output_block, bool* eos) { DCHECK(_child_block != nullptr); @@ -156,7 +146,7 @@ Status VTableFunctionNode::get_expanded_block(RuntimeState* state, Block* output } // if any table function is not outer and has empty result, go to next child row - if ((skip_child_row = _is_inner_and_empty()) == true) { + if (skip_child_row = _is_inner_and_empty(); skip_child_row) { continue; } @@ -225,7 +215,7 @@ Status VTableFunctionNode::_process_next_child_row() { RETURN_IF_ERROR(fn->process_close()); } - release_block_memory(*_child_block.get()); + release_block_memory(*_child_block); _cur_child_offset = -1; return Status::OK(); } diff --git a/be/src/vec/exec/vtable_function_node.h b/be/src/vec/exec/vtable_function_node.h index 6192e52ff6..1913cd1d35 100644 --- a/be/src/vec/exec/vtable_function_node.h +++ b/be/src/vec/exec/vtable_function_node.h @@ -37,8 +37,6 @@ private: Status get_expanded_block(RuntimeState* state, Block* output_block, bool* eos); - bool _is_inner_and_empty(); - std::unique_ptr _child_block; std::vector _child_slots; std::vector _output_slots; diff --git a/be/src/vec/functions/function_fake.cpp b/be/src/vec/functions/function_fake.cpp index 1f52297806..faf8d0d525 100644 --- a/be/src/vec/functions/function_fake.cpp +++ b/be/src/vec/functions/function_fake.cpp @@ -21,33 +21,21 @@ #include #include +#include "vec/data_types/data_type_nullable.h" + namespace doris::vectorized { -// We can use std::basic_fixed_string with c++20 in the future -template -struct FakeFunctionBaseImpl { - static constexpr auto name = Name; +template +struct FunctionFakeBaseImpl { static DataTypePtr get_return_type_impl(const DataTypes& arguments) { + if constexpr (AlwaysNullable) { + return make_nullable(std::make_shared()); + } return std::make_shared(); } }; -#define C_STR(str_) boost::mpl::c_str::value - -using FunctionEsquery = FakeFunctionBaseImpl; - -using FunctionExplodeSplit = FakeFunctionBaseImpl; -using FunctionExplodeNumbers = FakeFunctionBaseImpl; -using FunctionExplodeJsonArrayInt = - FakeFunctionBaseImpl; -using FunctionExplodeJsonArrayString = - FakeFunctionBaseImpl; -using FunctionExplodeJsonArrayDouble = - FakeFunctionBaseImpl; -using FunctionExplodeBitmap = FakeFunctionBaseImpl; - 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( @@ -55,16 +43,49 @@ struct FunctionExplode { } }; -void register_function_fake(SimpleFunctionFactory& factory) { - factory.register_function>(); +template +void register_function_default(SimpleFunctionFactory& factory, const std::string& name) { + factory.register_function>>(name); +}; - factory.register_table_function>(); - factory.register_table_function>(); - factory.register_table_function>(); - factory.register_table_function>(); - factory.register_table_function>(); - factory.register_table_function>(); - factory.register_table_function>(); +template +void register_table_function_expand(SimpleFunctionFactory& factory, const std::string& name, + const std::string& suffix) { + factory.register_function>(name); + factory.register_function>(name + suffix); +}; + +template +void register_table_function_expand_default(SimpleFunctionFactory& factory, const std::string& name, + const std::string& suffix) { + factory.register_function>>(name); + factory.register_function>>(name + suffix); +}; + +template +void register_table_function_expand_outer(SimpleFunctionFactory& factory, const std::string& name) { + register_table_function_expand(factory, name, COMBINATOR_SUFFIX_OUTER); +}; + +template +void register_table_function_expand_outer_default(SimpleFunctionFactory& factory, + const std::string& name) { + register_table_function_expand_default(factory, name, COMBINATOR_SUFFIX_OUTER); +}; + +void register_function_fake(SimpleFunctionFactory& factory) { + register_function_default(factory, "esquery"); + + register_table_function_expand_outer(factory, "explode"); + + register_table_function_expand_outer_default(factory, "explode_split"); + register_table_function_expand_outer_default(factory, "explode_numbers"); + register_table_function_expand_outer_default(factory, "explode_json_array_int"); + register_table_function_expand_outer_default(factory, + "explode_json_array_string"); + register_table_function_expand_outer_default(factory, + "explode_json_array_double"); + register_table_function_expand_outer_default(factory, "explode_bitmap"); } } // namespace doris::vectorized diff --git a/be/src/vec/functions/function_fake.h b/be/src/vec/functions/function_fake.h index eaaecaf843..2dbf4f263f 100644 --- a/be/src/vec/functions/function_fake.h +++ b/be/src/vec/functions/function_fake.h @@ -20,6 +20,7 @@ #include "common/status.h" #include "vec/core/types.h" #include "vec/data_types/data_type_array.h" +#include "vec/data_types/data_type_nullable.h" #include "vec/data_types/data_type_number.h" #include "vec/data_types/data_type_string.h" #include "vec/functions/function_helpers.h" @@ -31,7 +32,7 @@ namespace doris::vectorized { template class FunctionFake : public IFunction { public: - static constexpr auto name = Impl::name; + static constexpr auto name = "fake"; static FunctionPtr create() { return std::make_shared(); } diff --git a/be/src/vec/functions/simple_function_factory.h b/be/src/vec/functions/simple_function_factory.h index 033682212a..986528f25f 100644 --- a/be/src/vec/functions/simple_function_factory.h +++ b/be/src/vec/functions/simple_function_factory.h @@ -112,10 +112,8 @@ public: } template - void register_table_function() { - function_creators[Function::name] = &createDefaultFunction; - function_creators[std::string(Function::name) + COMBINATOR_SUFFIX_OUTER] = - &createDefaultFunction; + void register_function(std::string name) { + function_creators[name] = &createDefaultFunction; } void register_alias(const std::string& name, const std::string& alias) { diff --git a/regression-test/data/query/sql_functions/table_function/explode_json_array.out b/regression-test/data/query/sql_functions/table_function/explode_json_array.out index 52e504bdfb..4170e82089 100644 --- a/regression-test/data/query/sql_functions/table_function/explode_json_array.out +++ b/regression-test/data/query/sql_functions/table_function/explode_json_array.out @@ -22,10 +22,6 @@ 60 8 -- !explode_json_array3 -- -100 John 30 1 Street 1 \N -200 Mary \N 1 Street 2 \N -300 Mike 80 3 Street 3 \N -400 Dan 50 4 Street 4 \N -- !explode_json_array4 -- 100 John 30 1 Street 1 1.23 1