This is an automated email from the ASF dual-hosted git repository.
zhangstar333 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 360d354bcaf [feature](table-function)support posexplode table function
(#43221)
360d354bcaf is described below
commit 360d354bcaf0073342ad8ac5cd75ca2f96dc8246
Author: zhangstar333 <[email protected]>
AuthorDate: Wed Nov 6 15:29:34 2024 +0800
[feature](table-function)support posexplode table function (#43221)
### What problem does this PR solve?
<!--
You need to clearly describe your PR in this part:
1. What problem was fixed (it's best to include specific error reporting
information). How it was fixed.
2. Which behaviors were modified. What was the previous behavior, what
is it now, why was it modified, and what possible impacts might there
be.
3. What features were added. Why this function was added.
4. Which codes were refactored and why this part of the code was
refactored.
5. Which functions were optimized and what is the difference before and
after the optimization.
The description of the PR needs to enable reviewers to quickly and
clearly understand the logic of the code modification.
-->
<!--
If there are related issues, please fill in the issue number.
- If you want the issue to be closed after the PR is merged, please use
"close #12345". Otherwise, use "ref #12345"
-->
Issue Number: close #xxx
<!--
If this PR is followup a preivous PR, for example, fix the bug that
introduced by a related PR,
link the PR here
-->
Related PR: #xxx
Problem Summary:
support posexplode table function
doc: https://github.com/apache/doris-website/pull/1283
---
.../table_function/table_function_factory.cpp | 2 +
be/src/vec/exprs/table_function/vposexplode.cpp | 155 +++++++++++++++++++
be/src/vec/exprs/table_function/vposexplode.h | 50 +++++++
be/src/vec/functions/function_fake.cpp | 29 ++++
.../catalog/BuiltinTableGeneratingFunctions.java | 6 +-
.../functions/generator/PosExplode.java | 80 ++++++++++
.../functions/generator/PosExplodeOuter.java | 80 ++++++++++
.../visitor/TableGeneratingFunctionVisitor.java | 10 ++
.../sql_functions/table_function/posexplode.out | 166 +++++++++++++++++++++
.../sql_functions/table_function/posexplode.groovy | 82 ++++++++++
10 files changed, 659 insertions(+), 1 deletion(-)
diff --git a/be/src/vec/exprs/table_function/table_function_factory.cpp
b/be/src/vec/exprs/table_function/table_function_factory.cpp
index 0bef185351d..332eaed37d4 100644
--- a/be/src/vec/exprs/table_function/table_function_factory.cpp
+++ b/be/src/vec/exprs/table_function/table_function_factory.cpp
@@ -33,6 +33,7 @@
#include "vec/exprs/table_function/vexplode_map.h"
#include "vec/exprs/table_function/vexplode_numbers.h"
#include "vec/exprs/table_function/vexplode_split.h"
+#include "vec/exprs/table_function/vposexplode.h"
#include "vec/utils/util.hpp"
namespace doris::vectorized {
@@ -61,6 +62,7 @@ const std::unordered_map<std::string,
std::function<std::unique_ptr<TableFunctio
{"explode_bitmap",
TableFunctionCreator<VExplodeBitmapTableFunction>()},
{"explode_map", TableFunctionCreator<VExplodeMapTableFunction>
{}},
{"explode_json_object",
TableFunctionCreator<VExplodeJsonObjectTableFunction> {}},
+ {"posexplode", TableFunctionCreator<VPosExplodeTableFunction>
{}},
{"explode", TableFunctionCreator<VExplodeTableFunction> {}}};
Status TableFunctionFactory::get_fn(const TFunction& t_fn, ObjectPool* pool,
TableFunction** fn) {
diff --git a/be/src/vec/exprs/table_function/vposexplode.cpp
b/be/src/vec/exprs/table_function/vposexplode.cpp
new file mode 100644
index 00000000000..20d04a219f8
--- /dev/null
+++ b/be/src/vec/exprs/table_function/vposexplode.cpp
@@ -0,0 +1,155 @@
+// 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 "vec/exprs/table_function/vposexplode.h"
+
+#include <glog/logging.h>
+
+#include <ostream>
+#include <vector>
+
+#include "common/status.h"
+#include "vec/columns/column.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/columns/columns_number.h"
+#include "vec/common/assert_cast.h"
+#include "vec/common/string_ref.h"
+#include "vec/core/block.h"
+#include "vec/core/column_with_type_and_name.h"
+#include "vec/exprs/vexpr.h"
+#include "vec/exprs/vexpr_context.h"
+
+namespace doris::vectorized {
+
+VPosExplodeTableFunction::VPosExplodeTableFunction() {
+ _fn_name = "posexplode";
+}
+
+Status VPosExplodeTableFunction::process_init(Block* block, RuntimeState*
state) {
+ CHECK(_expr_context->root()->children().size() == 1)
+ << "VPosExplodeTableFunction only support 1 child but has "
+ << _expr_context->root()->children().size();
+
+ int value_column_idx = -1;
+
RETURN_IF_ERROR(_expr_context->root()->children()[0]->execute(_expr_context.get(),
block,
+
&value_column_idx));
+
+ _collection_column =
+
block->get_by_position(value_column_idx).column->convert_to_full_column_if_const();
+
+ if (!extract_column_array_info(*_collection_column, _array_detail)) {
+ return Status::NotSupported("column type {} not supported now, only
support array",
+
block->get_by_position(value_column_idx).column->get_name());
+ }
+ if (is_column_nullable(*_collection_column)) {
+ _array_data_column =
+ assert_cast<const ColumnArray&>(
+ assert_cast<const
ColumnNullable&>(*_collection_column).get_nested_column())
+ .get_data_ptr();
+ } else {
+ _array_data_column = assert_cast<const
ColumnArray&>(*_collection_column).get_data_ptr();
+ }
+ return Status::OK();
+}
+
+void VPosExplodeTableFunction::process_row(size_t row_idx) {
+ DCHECK(row_idx < _collection_column->size());
+ TableFunction::process_row(row_idx);
+
+ if (!_array_detail.array_nullmap_data ||
!_array_detail.array_nullmap_data[row_idx]) {
+ _collection_offset = (*_array_detail.offsets_ptr)[row_idx - 1];
+ _cur_size = (*_array_detail.offsets_ptr)[row_idx] - _collection_offset;
+ }
+}
+
+void VPosExplodeTableFunction::process_close() {
+ _collection_column = nullptr;
+ _array_data_column = nullptr;
+ _array_detail.reset();
+ _collection_offset = 0;
+}
+
+void VPosExplodeTableFunction::get_same_many_values(MutableColumnPtr& column,
int length) {
+ // now we only support array column explode to struct column
+ size_t pos = _collection_offset + _cur_offset;
+ // if current is empty array row, also append a default value
+ if (current_empty()) {
+ column->insert_many_defaults(length);
+ return;
+ }
+ ColumnStruct* ret = nullptr;
+ // this _is_nullable is whole output column's nullable
+ if (_is_nullable) {
+ ret = assert_cast<ColumnStruct*>(
+
assert_cast<ColumnNullable*>(column.get())->get_nested_column_ptr().get());
+ assert_cast<ColumnUInt8*>(
+
assert_cast<ColumnNullable*>(column.get())->get_null_map_column_ptr().get())
+ ->insert_many_defaults(length);
+ } else if (column->is_column_struct()) {
+ ret = assert_cast<ColumnStruct*>(column.get());
+ } else {
+ throw Exception(ErrorCode::INTERNAL_ERROR,
+ "only support array column explode to struct column");
+ }
+ if (!ret || ret->tuple_size() != 2) {
+ throw Exception(
+ ErrorCode::INTERNAL_ERROR,
+ "only support array column explode to two column, but given:
", ret->tuple_size());
+ }
+ auto& pose_column_nullable =
assert_cast<ColumnNullable&>(ret->get_column(0));
+ pose_column_nullable.get_null_map_column().insert_many_defaults(length);
+ assert_cast<ColumnInt32&>(pose_column_nullable.get_nested_column())
+ .insert_many_vals(_cur_offset, length);
+ ret->get_column(1).insert_many_from(*_array_data_column, pos, length);
+}
+
+int VPosExplodeTableFunction::get_value(MutableColumnPtr& column, int
max_step) {
+ max_step = std::min(max_step, (int)(_cur_size - _cur_offset));
+ size_t pos = _collection_offset + _cur_offset;
+ if (current_empty()) {
+ column->insert_default();
+ max_step = 1;
+ } else {
+ ColumnStruct* struct_column = nullptr;
+ if (_is_nullable) {
+ auto* nullable_column = assert_cast<ColumnNullable*>(column.get());
+ struct_column =
+
assert_cast<ColumnStruct*>(nullable_column->get_nested_column_ptr().get());
+ auto* nullmap_column =
+
assert_cast<ColumnUInt8*>(nullable_column->get_null_map_column_ptr().get());
+ // here nullmap_column insert max_step many defaults as if
array[row_idx] is NULL
+ // will be not update value, _cur_size = 0, means current_empty;
+ // so here could insert directly
+ nullmap_column->insert_many_defaults(max_step);
+ } else {
+ struct_column = assert_cast<ColumnStruct*>(column.get());
+ }
+ if (!struct_column || struct_column->tuple_size() != 2) {
+ throw Exception(ErrorCode::INTERNAL_ERROR,
+ "only support array column explode to two column,
but given: ",
+ struct_column->tuple_size());
+ }
+ auto& pose_column_nullable =
assert_cast<ColumnNullable&>(struct_column->get_column(0));
+
pose_column_nullable.get_null_map_column().insert_many_defaults(max_step);
+ assert_cast<ColumnInt32&>(pose_column_nullable.get_nested_column())
+ .insert_range_of_integer(_cur_offset, _cur_offset + max_step);
+ struct_column->get_column(1).insert_range_from(*_array_data_column,
pos, max_step);
+ }
+ forward(max_step);
+ return max_step;
+}
+} // namespace doris::vectorized
diff --git a/be/src/vec/exprs/table_function/vposexplode.h
b/be/src/vec/exprs/table_function/vposexplode.h
new file mode 100644
index 00000000000..4e021fd58da
--- /dev/null
+++ b/be/src/vec/exprs/table_function/vposexplode.h
@@ -0,0 +1,50 @@
+// 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.
+
+#pragma once
+
+#include "common/status.h"
+#include "vec/columns/column_map.h"
+#include "vec/data_types/data_type.h"
+#include "vec/data_types/data_type_array.h"
+#include "vec/exprs/table_function/table_function.h"
+#include "vec/functions/array/function_array_utils.h"
+
+namespace doris::vectorized {
+
+class VPosExplodeTableFunction : public TableFunction {
+ ENABLE_FACTORY_CREATOR(VPosExplodeTableFunction);
+
+public:
+ VPosExplodeTableFunction();
+
+ ~VPosExplodeTableFunction() override = default;
+
+ Status process_init(Block* block, RuntimeState* state) override;
+ void process_row(size_t row_idx) override;
+ void process_close() override;
+ void get_same_many_values(MutableColumnPtr& column, int length) override;
+ int get_value(MutableColumnPtr& column, int max_step) override;
+
+private:
+ ColumnPtr _collection_column;
+ ColumnPtr _array_data_column;
+ ColumnArrayExecutionData _array_detail;
+ size_t _collection_offset; // start offset of array[row_idx]
+};
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/functions/function_fake.cpp
b/be/src/vec/functions/function_fake.cpp
index 6a4f6275e1a..646da600b50 100644
--- a/be/src/vec/functions/function_fake.cpp
+++ b/be/src/vec/functions/function_fake.cpp
@@ -21,6 +21,7 @@
#include <algorithm>
#include <boost/iterator/iterator_facade.hpp>
+#include <memory>
#include <ostream>
#include <string>
@@ -83,6 +84,25 @@ struct FunctionExplodeMap {
static std::string get_error_msg() { return "Fake function do not support
execute"; }
};
+template <bool AlwaysNullable = false>
+struct FunctionPoseExplode {
+ static DataTypePtr get_return_type_impl(const DataTypes& arguments) {
+ DCHECK(is_array(arguments[0])) << arguments[0]->get_name() << " not
supported";
+ DataTypes fieldTypes(2);
+ fieldTypes[0] = make_nullable(std::make_shared<DataTypeInt32>());
+ fieldTypes[1] =
+
check_and_get_data_type<DataTypeArray>(arguments[0].get())->get_nested_type();
+ auto struct_type =
std::make_shared<vectorized::DataTypeStruct>(fieldTypes);
+ if constexpr (AlwaysNullable) {
+ return make_nullable(struct_type);
+ } else {
+ return arguments[0]->is_nullable() ? make_nullable(struct_type) :
struct_type;
+ }
+ }
+ static DataTypes get_variadic_argument_types() { return {}; }
+ static std::string get_error_msg() { return "Fake function do not support
execute"; }
+};
+
// explode json-object: expands json-object to struct with a pair of key and
value in column string
struct FunctionExplodeJsonObject {
static DataTypePtr get_return_type_impl(const DataTypes& arguments) {
@@ -138,6 +158,12 @@ void
register_table_function_expand_outer_default(SimpleFunctionFactory& factory
COMBINATOR_SUFFIX_OUTER);
};
+template <typename FunctionImpl>
+void register_table_function_with_impl(SimpleFunctionFactory& factory, const
std::string& name,
+ const std::string& suffix = "") {
+ factory.register_function<FunctionFake<FunctionImpl>>(name + suffix);
+};
+
void register_function_fake(SimpleFunctionFactory& factory) {
register_function<FunctionEsquery>(factory, "esquery");
@@ -158,6 +184,9 @@ void register_function_fake(SimpleFunctionFactory& factory)
{
register_table_function_expand_outer_default<DataTypeFloat64, false>(
factory, "explode_json_array_double");
register_table_function_expand_outer_default<DataTypeInt64,
false>(factory, "explode_bitmap");
+ register_table_function_with_impl<FunctionPoseExplode<false>>(factory,
"posexplode");
+ register_table_function_with_impl<FunctionPoseExplode<true>>(factory,
"posexplode",
+
COMBINATOR_SUFFIX_OUTER);
register_table_function_expand_outer_default<DataTypeObject,
false>(factory,
"explode_variant_array");
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinTableGeneratingFunctions.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinTableGeneratingFunctions.java
index 8f9679a0b51..d342b01ff7e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinTableGeneratingFunctions.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinTableGeneratingFunctions.java
@@ -38,6 +38,8 @@ import
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeOut
import
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeSplit;
import
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeSplitOuter;
import
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeVariantArray;
+import
org.apache.doris.nereids.trees.expressions.functions.generator.PosExplode;
+import
org.apache.doris.nereids.trees.expressions.functions.generator.PosExplodeOuter;
import com.google.common.collect.ImmutableList;
@@ -71,7 +73,9 @@ public class BuiltinTableGeneratingFunctions implements
FunctionHelper {
tableGenerating(ExplodeJsonArrayStringOuter.class,
"explode_json_array_string_outer"),
tableGenerating(ExplodeJsonArrayJson.class,
"explode_json_array_json"),
tableGenerating(ExplodeJsonArrayJsonOuter.class,
"explode_json_array_json_outer"),
- tableGenerating(ExplodeVariantArray.class, "explode_variant_array")
+ tableGenerating(ExplodeVariantArray.class,
"explode_variant_array"),
+ tableGenerating(PosExplode.class, "posexplode"),
+ tableGenerating(PosExplodeOuter.class, "posexplode_outer")
);
public static final BuiltinTableGeneratingFunctions INSTANCE = new
BuiltinTableGeneratingFunctions();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/PosExplode.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/PosExplode.java
new file mode 100644
index 00000000000..16f8232606f
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/PosExplode.java
@@ -0,0 +1,80 @@
+// 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.
+
+package org.apache.doris.nereids.trees.expressions.functions.generator;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.ArrayType;
+import org.apache.doris.nereids.types.IntegerType;
+import org.apache.doris.nereids.types.StructField;
+import org.apache.doris.nereids.types.StructType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * PosExplode(array('a','b','c')) generate two columns and three rows with:
+ * pose column: 0, 1, 2
+ * value column: 'a', 'b', 'c'
+ */
+public class PosExplode extends TableGeneratingFunction implements
UnaryExpression, PropagateNullable {
+
+ /**
+ * constructor with 1 argument.
+ */
+ public PosExplode(Expression arg) {
+ super("posexplode", arg);
+ }
+
+ /**
+ * withChildren.
+ */
+ @Override
+ public PosExplode withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 1);
+ return new PosExplode(children.get(0));
+ }
+
+ @Override
+ public void checkLegalityBeforeTypeCoercion() {
+ if (!(child().getDataType() instanceof ArrayType)) {
+ throw new AnalysisException("only support array type for
posexplode function but got "
+ + child().getDataType());
+ }
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return ImmutableList.of(
+ FunctionSignature.ret(new StructType(ImmutableList.of(
+ new StructField("pos", IntegerType.INSTANCE, true, ""),
+ new StructField("col", ((ArrayType)
child().getDataType()).getItemType(), true, ""))))
+ .args(child().getDataType()));
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitPosExplode(this, context);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/PosExplodeOuter.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/PosExplodeOuter.java
new file mode 100644
index 00000000000..6d181354f41
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/PosExplodeOuter.java
@@ -0,0 +1,80 @@
+// 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.
+
+package org.apache.doris.nereids.trees.expressions.functions.generator;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable;
+import org.apache.doris.nereids.trees.expressions.literal.StructLiteral;
+import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.ArrayType;
+import org.apache.doris.nereids.types.IntegerType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * PosExplode(array('a','b','c')) generate two columns and three rows with:
+ * pose column: 0, 1, 2
+ * value column: 'a', 'b', 'c'
+ */
+public class PosExplodeOuter extends TableGeneratingFunction implements
UnaryExpression, AlwaysNullable {
+
+ /**
+ * constructor with 1 argument.
+ */
+ public PosExplodeOuter(Expression arg) {
+ super("posexplode_outer", arg);
+ }
+
+ /**
+ * withChildren.
+ */
+ @Override
+ public PosExplodeOuter withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 1);
+ return new PosExplodeOuter(children.get(0));
+ }
+
+ @Override
+ public void checkLegalityBeforeTypeCoercion() {
+ if (!(child().getDataType() instanceof ArrayType)) {
+ throw new AnalysisException("only support array type for
posexplode_outer function but got "
+ + child().getDataType());
+ }
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return ImmutableList.of(
+ FunctionSignature.ret(StructLiteral.constructStructType(
+ Lists.newArrayList(IntegerType.INSTANCE,
+ ((ArrayType)
child().getDataType()).getItemType())))
+ .args(child().getDataType()));
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitPosExplodeOuter(this, context);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/TableGeneratingFunctionVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/TableGeneratingFunctionVisitor.java
index 94839b21fe7..9fae7c397ca 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/TableGeneratingFunctionVisitor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/TableGeneratingFunctionVisitor.java
@@ -38,6 +38,8 @@ import
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeOut
import
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeSplit;
import
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeSplitOuter;
import
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeVariantArray;
+import
org.apache.doris.nereids.trees.expressions.functions.generator.PosExplode;
+import
org.apache.doris.nereids.trees.expressions.functions.generator.PosExplodeOuter;
import
org.apache.doris.nereids.trees.expressions.functions.generator.TableGeneratingFunction;
import org.apache.doris.nereids.trees.expressions.functions.udf.JavaUdtf;
@@ -134,4 +136,12 @@ public interface TableGeneratingFunctionVisitor<R, C> {
default R visitJavaUdtf(JavaUdtf udtf, C context) {
return visitTableGeneratingFunction(udtf, context);
}
+
+ default R visitPosExplode(PosExplode posExplode, C context) {
+ return visitTableGeneratingFunction(posExplode, context);
+ }
+
+ default R visitPosExplodeOuter(PosExplodeOuter posExplodeOuter, C context)
{
+ return visitTableGeneratingFunction(posExplodeOuter, context);
+ }
}
diff --git
a/regression-test/data/nereids_p0/sql_functions/table_function/posexplode.out
b/regression-test/data/nereids_p0/sql_functions/table_function/posexplode.out
new file mode 100644
index 00000000000..393e13a2b54
--- /dev/null
+++
b/regression-test/data/nereids_p0/sql_functions/table_function/posexplode.out
@@ -0,0 +1,166 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !sql --
+0 zhangsan ["Chinese", "Math", "English"]
+1 lisi ["null"]
+2 wangwu ["88a", "90b", "96c"]
+3 lisi2 [null]
+4 amory \N
+
+-- !explode_sql --
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese
+0 zhangsan ["Chinese", "Math", "English"] 1 Math
+0 zhangsan ["Chinese", "Math", "English"] 2 English
+1 lisi ["null"] 0 null
+2 wangwu ["88a", "90b", "96c"] 0 88a
+2 wangwu ["88a", "90b", "96c"] 1 90b
+2 wangwu ["88a", "90b", "96c"] 2 96c
+3 lisi2 [null] 0 \N
+
+-- !explode_outer_sql --
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese
+0 zhangsan ["Chinese", "Math", "English"] 1 Math
+0 zhangsan ["Chinese", "Math", "English"] 2 English
+1 lisi ["null"] 0 null
+2 wangwu ["88a", "90b", "96c"] 0 88a
+2 wangwu ["88a", "90b", "96c"] 1 90b
+2 wangwu ["88a", "90b", "96c"] 2 96c
+3 lisi2 [null] 0 \N
+4 amory \N \N \N
+
+-- !explode_sql_multi --
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese 0
Chinese
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese 1
Math
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese 2
English
+0 zhangsan ["Chinese", "Math", "English"] 1 Math 0
Chinese
+0 zhangsan ["Chinese", "Math", "English"] 1 Math 1
Math
+0 zhangsan ["Chinese", "Math", "English"] 1 Math 2
English
+0 zhangsan ["Chinese", "Math", "English"] 2 English 0
Chinese
+0 zhangsan ["Chinese", "Math", "English"] 2 English 1
Math
+0 zhangsan ["Chinese", "Math", "English"] 2 English 2
English
+1 lisi ["null"] 0 null 0 null
+2 wangwu ["88a", "90b", "96c"] 0 88a 0 88a
+2 wangwu ["88a", "90b", "96c"] 0 88a 1 90b
+2 wangwu ["88a", "90b", "96c"] 0 88a 2 96c
+2 wangwu ["88a", "90b", "96c"] 1 90b 0 88a
+2 wangwu ["88a", "90b", "96c"] 1 90b 1 90b
+2 wangwu ["88a", "90b", "96c"] 1 90b 2 96c
+2 wangwu ["88a", "90b", "96c"] 2 96c 0 88a
+2 wangwu ["88a", "90b", "96c"] 2 96c 1 90b
+2 wangwu ["88a", "90b", "96c"] 2 96c 2 96c
+3 lisi2 [null] 0 \N 0 \N
+
+-- !explode_sql_alias --
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese
+0 zhangsan ["Chinese", "Math", "English"] 1 Math
+0 zhangsan ["Chinese", "Math", "English"] 2 English
+1 lisi ["null"] 0 null
+2 wangwu ["88a", "90b", "96c"] 0 88a
+2 wangwu ["88a", "90b", "96c"] 1 90b
+2 wangwu ["88a", "90b", "96c"] 2 96c
+3 lisi2 [null] 0 \N
+
+-- !explode_outer_sql_alias --
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese
+0 zhangsan ["Chinese", "Math", "English"] 1 Math
+0 zhangsan ["Chinese", "Math", "English"] 2 English
+1 lisi ["null"] 0 null
+2 wangwu ["88a", "90b", "96c"] 0 88a
+2 wangwu ["88a", "90b", "96c"] 1 90b
+2 wangwu ["88a", "90b", "96c"] 2 96c
+3 lisi2 [null] 0 \N
+4 amory \N \N \N
+
+-- !explode_sql_alias_multi --
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese 0
Chinese
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese 1
Math
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese 2
English
+0 zhangsan ["Chinese", "Math", "English"] 1 Math 0
Chinese
+0 zhangsan ["Chinese", "Math", "English"] 1 Math 1
Math
+0 zhangsan ["Chinese", "Math", "English"] 1 Math 2
English
+0 zhangsan ["Chinese", "Math", "English"] 2 English 0
Chinese
+0 zhangsan ["Chinese", "Math", "English"] 2 English 1
Math
+0 zhangsan ["Chinese", "Math", "English"] 2 English 2
English
+1 lisi ["null"] 0 null 0 null
+2 wangwu ["88a", "90b", "96c"] 0 88a 0 88a
+2 wangwu ["88a", "90b", "96c"] 0 88a 1 90b
+2 wangwu ["88a", "90b", "96c"] 0 88a 2 96c
+2 wangwu ["88a", "90b", "96c"] 1 90b 0 88a
+2 wangwu ["88a", "90b", "96c"] 1 90b 1 90b
+2 wangwu ["88a", "90b", "96c"] 1 90b 2 96c
+2 wangwu ["88a", "90b", "96c"] 2 96c 0 88a
+2 wangwu ["88a", "90b", "96c"] 2 96c 1 90b
+2 wangwu ["88a", "90b", "96c"] 2 96c 2 96c
+3 lisi2 [null] 0 \N 0 \N
+
+-- !sql --
+0 zhangsan ["Chinese", "Math", "English"]
+1 lisi ["null"]
+2 wangwu ["88a", "90b", "96c"]
+3 lisi2 [null]
+4 liuba []
+
+-- !explode_sql_not --
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese
+0 zhangsan ["Chinese", "Math", "English"] 1 Math
+0 zhangsan ["Chinese", "Math", "English"] 2 English
+1 lisi ["null"] 0 null
+2 wangwu ["88a", "90b", "96c"] 0 88a
+2 wangwu ["88a", "90b", "96c"] 1 90b
+2 wangwu ["88a", "90b", "96c"] 2 96c
+3 lisi2 [null] 0 \N
+
+-- !explode_outer_sql_not --
+0 zhangsan ["Chinese", "Math", "English"] 0 Chinese
+0 zhangsan ["Chinese", "Math", "English"] 1 Math
+0 zhangsan ["Chinese", "Math", "English"] 2 English
+1 lisi ["null"] 0 null
+2 wangwu ["88a", "90b", "96c"] 0 88a
+2 wangwu ["88a", "90b", "96c"] 1 90b
+2 wangwu ["88a", "90b", "96c"] 2 96c
+3 lisi2 [null] 0 \N
+4 liuba [] \N \N
+
+-- !explode_sql_alias_multi2 --
+0 zhangsan ["Chinese", "Math", "English"] {"pos":0,
"col":"Chinese"} {"pos":0, "col":"Chinese"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":0,
"col":"Chinese"} {"pos":1, "col":"Math"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":0,
"col":"Chinese"} {"pos":2, "col":"English"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":1, "col":"Math"}
{"pos":0, "col":"Chinese"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":1, "col":"Math"}
{"pos":1, "col":"Math"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":1, "col":"Math"}
{"pos":2, "col":"English"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":2,
"col":"English"} {"pos":0, "col":"Chinese"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":2,
"col":"English"} {"pos":1, "col":"Math"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":2,
"col":"English"} {"pos":2, "col":"English"}
+1 lisi ["null"] {"pos":0, "col":"null"} {"pos":0, "col":"null"}
+2 wangwu ["88a", "90b", "96c"] {"pos":0, "col":"88a"} {"pos":0,
"col":"88a"}
+2 wangwu ["88a", "90b", "96c"] {"pos":0, "col":"88a"} {"pos":1,
"col":"90b"}
+2 wangwu ["88a", "90b", "96c"] {"pos":0, "col":"88a"} {"pos":2,
"col":"96c"}
+2 wangwu ["88a", "90b", "96c"] {"pos":1, "col":"90b"} {"pos":0,
"col":"88a"}
+2 wangwu ["88a", "90b", "96c"] {"pos":1, "col":"90b"} {"pos":1,
"col":"90b"}
+2 wangwu ["88a", "90b", "96c"] {"pos":1, "col":"90b"} {"pos":2,
"col":"96c"}
+2 wangwu ["88a", "90b", "96c"] {"pos":2, "col":"96c"} {"pos":0,
"col":"88a"}
+2 wangwu ["88a", "90b", "96c"] {"pos":2, "col":"96c"} {"pos":1,
"col":"90b"}
+2 wangwu ["88a", "90b", "96c"] {"pos":2, "col":"96c"} {"pos":2,
"col":"96c"}
+3 lisi2 [null] {"pos":0, "col":null} {"pos":0, "col":null}
+
+-- !explode_sql_alias_multi3 --
+0 zhangsan ["Chinese", "Math", "English"] {"pos":0,
"col":"Chinese"} {"pos":0, "col":"Chinese"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":0,
"col":"Chinese"} {"pos":1, "col":"Math"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":0,
"col":"Chinese"} {"pos":2, "col":"English"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":1, "col":"Math"}
{"pos":0, "col":"Chinese"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":1, "col":"Math"}
{"pos":1, "col":"Math"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":1, "col":"Math"}
{"pos":2, "col":"English"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":2,
"col":"English"} {"pos":0, "col":"Chinese"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":2,
"col":"English"} {"pos":1, "col":"Math"}
+0 zhangsan ["Chinese", "Math", "English"] {"pos":2,
"col":"English"} {"pos":2, "col":"English"}
+1 lisi ["null"] {"pos":0, "col":"null"} {"pos":0, "col":"null"}
+2 wangwu ["88a", "90b", "96c"] {"pos":0, "col":"88a"} {"pos":0,
"col":"88a"}
+2 wangwu ["88a", "90b", "96c"] {"pos":0, "col":"88a"} {"pos":1,
"col":"90b"}
+2 wangwu ["88a", "90b", "96c"] {"pos":0, "col":"88a"} {"pos":2,
"col":"96c"}
+2 wangwu ["88a", "90b", "96c"] {"pos":1, "col":"90b"} {"pos":0,
"col":"88a"}
+2 wangwu ["88a", "90b", "96c"] {"pos":1, "col":"90b"} {"pos":1,
"col":"90b"}
+2 wangwu ["88a", "90b", "96c"] {"pos":1, "col":"90b"} {"pos":2,
"col":"96c"}
+2 wangwu ["88a", "90b", "96c"] {"pos":2, "col":"96c"} {"pos":0,
"col":"88a"}
+2 wangwu ["88a", "90b", "96c"] {"pos":2, "col":"96c"} {"pos":1,
"col":"90b"}
+2 wangwu ["88a", "90b", "96c"] {"pos":2, "col":"96c"} {"pos":2,
"col":"96c"}
+3 lisi2 [null] {"pos":0, "col":null} {"pos":0, "col":null}
+
diff --git
a/regression-test/suites/nereids_p0/sql_functions/table_function/posexplode.groovy
b/regression-test/suites/nereids_p0/sql_functions/table_function/posexplode.groovy
new file mode 100644
index 00000000000..8320af92f48
--- /dev/null
+++
b/regression-test/suites/nereids_p0/sql_functions/table_function/posexplode.groovy
@@ -0,0 +1,82 @@
+// 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("posexplode") {
+ sql "SET enable_nereids_planner=true"
+ sql "SET enable_fallback_to_original_planner=false"
+
+ sql """ DROP TABLE IF EXISTS table_test """
+ sql """
+ CREATE TABLE IF NOT EXISTS `table_test`(
+ `id` INT NULL,
+ `name` TEXT NULL,
+ `score` array<string> NULL
+ ) ENGINE=OLAP
+ DUPLICATE KEY(`id`)
+ COMMENT 'OLAP'
+ DISTRIBUTED BY HASH(`id`) BUCKETS 1
+ PROPERTIES ("replication_allocation" = "tag.location.default:
1");
+ """
+
+ // insert values
+ sql """ insert into table_test values (0, "zhangsan",
["Chinese","Math","English"]); """
+ sql """ insert into table_test values (1, "lisi", ["null"]); """
+ sql """ insert into table_test values (2, "wangwu", ["88a","90b","96c"]);
"""
+ sql """ insert into table_test values (3, "lisi2", [null]); """
+ sql """ insert into table_test values (4, "amory", NULL); """
+
+ qt_sql """ select * from table_test order by id; """
+ order_qt_explode_sql """ select id,name,score, k,v from table_test lateral
view posexplode(score) tmp as k,v order by id;"""
+ order_qt_explode_outer_sql """ select id,name,score, k,v from table_test
lateral view posexplode_outer(score) tmp as k,v order by id; """
+
+ // multi lateral view
+ order_qt_explode_sql_multi """ select id,name,score, k,v,k1,v1 from
table_test lateral view posexplode_outer(score) tmp as k,v lateral view
posexplode(score) tmp2 as k1,v1 order by id;"""
+
+ // test with alias
+ order_qt_explode_sql_alias """ select id,name,score, tmp.k, tmp.v from
table_test lateral view posexplode(score) tmp as k,v order by id;"""
+ order_qt_explode_outer_sql_alias """ select id,name,score, tmp.k, tmp.v
from table_test lateral view posexplode_outer(score) tmp as k,v order by id; """
+
+ order_qt_explode_sql_alias_multi """ select id,name,score, tmp.k, tmp.v,
tmp2.k, tmp2.v from table_test lateral view posexplode_outer(score) tmp as k,v
lateral view posexplode(score) tmp2 as k,v order by id;"""
+
+ sql """ DROP TABLE IF EXISTS table_test_not """
+ sql """
+ CREATE TABLE IF NOT EXISTS `table_test_not`(
+ `id` INT NULL,
+ `name` TEXT NULL,
+ `score` array<string> not NULL
+ ) ENGINE=OLAP
+ DUPLICATE KEY(`id`)
+ COMMENT 'OLAP'
+ DISTRIBUTED BY HASH(`id`) BUCKETS 1
+ PROPERTIES ("replication_allocation" = "tag.location.default:
1");
+ """
+
+ // insert values
+ sql """ insert into table_test_not values (0, "zhangsan",
["Chinese","Math","English"]); """
+ sql """ insert into table_test_not values (1, "lisi", ["null"]); """
+ sql """ insert into table_test_not values (2, "wangwu",
["88a","90b","96c"]); """
+ sql """ insert into table_test_not values (3, "lisi2", [null]); """
+ sql """ insert into table_test_not values (4, "liuba", []); """
+
+ qt_sql """ select * from table_test_not order by id; """
+ order_qt_explode_sql_not """ select id,name,score, k,v from table_test_not
lateral view posexplode(score) tmp as k,v order by id;"""
+ order_qt_explode_outer_sql_not """ select id,name,score, k,v from
table_test_not lateral view posexplode_outer(score) tmp as k,v order by id; """
+ order_qt_explode_sql_alias_multi2 """ select * from table_test_not lateral
view posexplode(score) tmp as e1 lateral view posexplode(score) tmp2 as e2
order by id;"""
+ sql """ set batch_size = 1; """
+ order_qt_explode_sql_alias_multi3 """ select * from table_test_not lateral
view posexplode(score) tmp as e1 lateral view posexplode(score) tmp2 as e2
order by id;"""
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]