This is an automated email from the ASF dual-hosted git repository.

kxiao pushed a commit to branch branch-2.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.1 by this push:
     new 3cb1d4e842a [feature](json)support explode_json_object func #36887 
(#37378)
3cb1d4e842a is described below

commit 3cb1d4e842a4824b2ff4707f9bf76277233fa162
Author: amory <[email protected]>
AuthorDate: Tue Jul 16 10:59:11 2024 +0800

    [feature](json)support explode_json_object func #36887 (#37378)
---
 be/src/vec/exprs/table_function/table_function.h   |   1 +
 .../vec/exprs/table_function/vexplode_bitmap.cpp   |   2 +-
 .../vec/exprs/table_function/vexplode_json_array.h |   2 +-
 .../exprs/table_function/vexplode_json_object.cpp  | 160 +++++++++++++++++++++
 .../exprs/table_function/vexplode_json_object.h    |  59 ++++++++
 be/src/vec/functions/function_fake.cpp             |  14 ++
 .../catalog/BuiltinTableGeneratingFunctions.java   |   4 +
 .../functions/generator/ExplodeJsonObject.java     |  70 +++++++++
 .../generator/ExplodeJsonObjectOuter.java          |  68 +++++++++
 .../visitor/TableGeneratingFunctionVisitor.java    |  10 ++
 .../jsonb_p0/test_jsonb_load_and_function.out      |  79 +++++++++-
 .../jsonb_p0/test_jsonb_load_and_function.groovy   |   9 ++
 .../jsonb_p0/test_jsonb_load_and_function.groovy   |   4 +
 13 files changed, 478 insertions(+), 4 deletions(-)

diff --git a/be/src/vec/exprs/table_function/table_function.h 
b/be/src/vec/exprs/table_function/table_function.h
index bd926c36570..fc3d3882b50 100644
--- a/be/src/vec/exprs/table_function/table_function.h
+++ b/be/src/vec/exprs/table_function/table_function.h
@@ -54,6 +54,7 @@ public:
     }
 
     virtual void get_same_many_values(MutableColumnPtr& column, int length = 
0) = 0;
+
     virtual int get_value(MutableColumnPtr& column, int max_step) = 0;
 
     virtual Status close() { return Status::OK(); }
diff --git a/be/src/vec/exprs/table_function/vexplode_bitmap.cpp 
b/be/src/vec/exprs/table_function/vexplode_bitmap.cpp
index 5327c2e1633..e6e4c843075 100644
--- a/be/src/vec/exprs/table_function/vexplode_bitmap.cpp
+++ b/be/src/vec/exprs/table_function/vexplode_bitmap.cpp
@@ -90,7 +90,7 @@ void 
VExplodeBitmapTableFunction::get_same_many_values(MutableColumnPtr& column,
 
 void VExplodeBitmapTableFunction::process_row(size_t row_idx) {
     TableFunction::process_row(row_idx);
-    //FIXME: use ColumnComplex instead
+
     StringRef value = _value_column->get_data_at(row_idx);
 
     if (value.data) {
diff --git a/be/src/vec/exprs/table_function/vexplode_json_array.h 
b/be/src/vec/exprs/table_function/vexplode_json_array.h
index 968fa5e91a4..1d89d9fa57d 100644
--- a/be/src/vec/exprs/table_function/vexplode_json_array.h
+++ b/be/src/vec/exprs/table_function/vexplode_json_array.h
@@ -269,4 +269,4 @@ private:
     ColumnPtr _text_column;
 };
 
-} // namespace doris::vectorized
\ No newline at end of file
+} // namespace doris::vectorized
diff --git a/be/src/vec/exprs/table_function/vexplode_json_object.cpp 
b/be/src/vec/exprs/table_function/vexplode_json_object.cpp
new file mode 100644
index 00000000000..1981f48f62c
--- /dev/null
+++ b/be/src/vec/exprs/table_function/vexplode_json_object.cpp
@@ -0,0 +1,160 @@
+// 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/vexplode_json_object.h"
+
+#include <glog/logging.h>
+
+#include <ostream>
+#include <vector>
+
+#include "common/status.h"
+#include "vec/columns/column.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 {
+
+VExplodeJsonObjectTableFunction::VExplodeJsonObjectTableFunction() {
+    _fn_name = "vexplode_json_object";
+}
+
+Status VExplodeJsonObjectTableFunction::process_init(Block* block, 
RuntimeState* state) {
+    CHECK(_expr_context->root()->children().size() == 1)
+            << "VExplodeJsonObjectTableFunction only support 1 child but has "
+            << _expr_context->root()->children().size();
+
+    int text_column_idx = -1;
+    
RETURN_IF_ERROR(_expr_context->root()->children()[0]->execute(_expr_context.get(),
 block,
+                                                                  
&text_column_idx));
+
+    _json_object_column = block->get_by_position(text_column_idx).column;
+    return Status::OK();
+}
+
+void VExplodeJsonObjectTableFunction::process_row(size_t row_idx) {
+    TableFunction::process_row(row_idx);
+
+    StringRef text = _json_object_column->get_data_at(row_idx);
+    if (text.data != nullptr) {
+        JsonbDocument* doc = JsonbDocument::createDocument(text.data, 
text.size);
+        if (UNLIKELY(!doc || !doc->getValue())) {
+            // error jsonb, put null into output, cur_size = 0 , we will 
insert_default
+            return;
+        }
+        // value is NOT necessary to be deleted since JsonbValue will not 
allocate memory
+        JsonbValue* value = doc->getValue();
+        auto writer = std::make_unique<JsonbWriter>();
+        if (value->isObject()) {
+            _cur_size = value->length();
+            ObjectVal* obj = (ObjectVal*)value;
+            _object_pairs.first =
+                    ColumnNullable::create(ColumnString::create(), 
ColumnUInt8::create());
+            _object_pairs.second =
+                    ColumnNullable::create(ColumnString::create(), 
ColumnUInt8::create());
+            _object_pairs.first->reserve(_cur_size);
+            _object_pairs.second->reserve(_cur_size);
+            for (auto it = obj->begin(); it != obj->end(); ++it) {
+                _object_pairs.first->insert_data(it->getKeyStr(), it->klen());
+                writer->reset();
+                writer->writeValue(it->value());
+                if (it->value()->isNull()) {
+                    _object_pairs.second->insert_default();
+                } else {
+                    const std::string_view& jsonb_value = std::string_view(
+                            writer->getOutput()->getBuffer(), 
writer->getOutput()->getSize());
+                    _object_pairs.second->insert_data(jsonb_value.data(), 
jsonb_value.size());
+                }
+            }
+        }
+        // we do not support other json type except object
+    }
+}
+
+void VExplodeJsonObjectTableFunction::process_close() {
+    _json_object_column = nullptr;
+    _object_pairs.first = nullptr;
+    _object_pairs.second = nullptr;
+}
+
+void VExplodeJsonObjectTableFunction::get_same_many_values(MutableColumnPtr& 
column, int length) {
+    // if current is empty map 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) {
+        // make map kv value into struct
+        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 expand json object int to struct(kv 
pair), but given: ",
+                        column->get_name());
+    }
+    if (!ret || ret->tuple_size() != 2) {
+        throw Exception(ErrorCode::INTERNAL_ERROR,
+                        "only support expand json object int to kv pair 
column, but given: ",
+                        ret->tuple_size());
+    }
+    ret->get_column(0).insert_many_from(*_object_pairs.first, _cur_offset, 
length);
+    ret->get_column(1).insert_many_from(*_object_pairs.second, _cur_offset, 
length);
+}
+
+int VExplodeJsonObjectTableFunction::get_value(MutableColumnPtr& column, int 
max_step) {
+    max_step = std::min(max_step, (int)(_cur_size - _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 
MAP[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 expand json object int to kv pair 
column, but given:  ",
+                            struct_column->tuple_size());
+        }
+        struct_column->get_column(0).insert_range_from(*_object_pairs.first, 
_cur_offset, max_step);
+        struct_column->get_column(1).insert_range_from(*_object_pairs.second, 
_cur_offset,
+                                                       max_step);
+    }
+    forward(max_step);
+    return max_step;
+}
+} // namespace doris::vectorized
diff --git a/be/src/vec/exprs/table_function/vexplode_json_object.h 
b/be/src/vec/exprs/table_function/vexplode_json_object.h
new file mode 100644
index 00000000000..9173fd9cbac
--- /dev/null
+++ b/be/src/vec/exprs/table_function/vexplode_json_object.h
@@ -0,0 +1,59 @@
+// 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 <stddef.h>
+
+#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/data_types/data_type_map.h"
+#include "vec/exprs/table_function/table_function.h"
+#include "vec/functions/array/function_array_utils.h"
+
+namespace doris::vectorized {
+class Block;
+} // namespace doris::vectorized
+
+namespace doris::vectorized {
+
+// explode_json_object("{\"a\": 1, \"b\": 2}") ->
+// | key | value |
+// | a   | 1     |
+// | b   | 2     |
+class VExplodeJsonObjectTableFunction : public TableFunction {
+    ENABLE_FACTORY_CREATOR(VExplodeJsonObjectTableFunction);
+
+public:
+    VExplodeJsonObjectTableFunction();
+
+    ~VExplodeJsonObjectTableFunction() 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 _json_object_column;
+    std::pair<MutableColumnPtr, MutableColumnPtr> _object_pairs; // 
ColumnNullable<ColumnString>
+};
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/functions/function_fake.cpp 
b/be/src/vec/functions/function_fake.cpp
index 2d8e258d529..0353b3a2a7c 100644
--- a/be/src/vec/functions/function_fake.cpp
+++ b/be/src/vec/functions/function_fake.cpp
@@ -70,6 +70,19 @@ struct FunctionExplodeMap {
     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) {
+        DCHECK(WhichDataType(arguments[0]).is_json())
+                << " explode json object " << arguments[0]->get_name() << " 
not supported";
+        DataTypes fieldTypes(2);
+        fieldTypes[0] = make_nullable(std::make_shared<DataTypeString>());
+        fieldTypes[1] = make_nullable(std::make_shared<DataTypeJsonb>());
+        return 
make_nullable(std::make_shared<vectorized::DataTypeStruct>(fieldTypes));
+    }
+    static std::string get_error_msg() { return "Fake function do not support 
execute"; }
+};
+
 struct FunctionEsquery {
     static DataTypePtr get_return_type_impl(const DataTypes& arguments) {
         return 
FunctionFakeBaseImpl<DataTypeUInt8>::get_return_type_impl(arguments);
@@ -113,6 +126,7 @@ void register_function_fake(SimpleFunctionFactory& factory) 
{
     register_table_function_expand_outer<FunctionExplode>(factory, "explode");
     register_table_function_expand_outer<FunctionExplodeMap>(factory, 
"explode_map");
 
+    register_table_function_expand_outer<FunctionExplodeJsonObject>(factory, 
"explode_json_object");
     register_table_function_expand_outer_default<DataTypeString>(factory, 
"explode_split");
     register_table_function_expand_outer_default<DataTypeInt32>(factory, 
"explode_numbers");
     register_table_function_expand_outer_default<DataTypeInt64>(factory, 
"explode_json_array_int");
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 6fab5cfc04e..84894db95c5 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
@@ -28,6 +28,8 @@ import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJso
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonArrayJsonOuter;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonArrayString;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonArrayStringOuter;
+import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonObject;
+import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonObjectOuter;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeMap;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeMapOuter;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeNumbers;
@@ -52,6 +54,8 @@ public class BuiltinTableGeneratingFunctions implements 
FunctionHelper {
             tableGenerating(ExplodeOuter.class, "explode_outer"),
             tableGenerating(ExplodeMap.class, "explode_map"),
             tableGenerating(ExplodeMapOuter.class, "explode_map_outer"),
+            tableGenerating(ExplodeJsonObject.class, "explode_json_object"),
+            tableGenerating(ExplodeJsonObjectOuter.class, 
"explode_json_object_outer"),
             tableGenerating(ExplodeNumbers.class, "explode_numbers"),
             tableGenerating(ExplodeNumbersOuter.class, 
"explode_numbers_outer"),
             tableGenerating(ExplodeBitmap.class, "explode_bitmap"),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/ExplodeJsonObject.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/ExplodeJsonObject.java
new file mode 100644
index 00000000000..e4546205b7f
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/ExplodeJsonObject.java
@@ -0,0 +1,70 @@
+// 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.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.JsonType;
+import org.apache.doris.nereids.types.StringType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * explode_json_object("{"amory":1, "doris": 2}") generate two column and two 
lines with:
+ *      key column: amory, doris
+ *      value column: 1, 2
+ */
+public class ExplodeJsonObject extends TableGeneratingFunction implements 
UnaryExpression, AlwaysNullable {
+
+    public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(StructLiteral.constructStructType(
+                    ImmutableList.of(StringType.INSTANCE, 
JsonType.INSTANCE))).args(JsonType.INSTANCE));
+
+    /**
+     * constructor with 1 argument.
+     */
+    public ExplodeJsonObject(Expression arg) {
+        super("explode_json_object", arg);
+    }
+
+    /**
+     * withChildren.
+     */
+    @Override
+    public ExplodeJsonObject withChildren(List<Expression> children) {
+        Preconditions.checkArgument(children.size() == 1);
+        return new ExplodeJsonObject(children.get(0));
+    }
+
+    @Override
+    public List<FunctionSignature> getSignatures() {
+        return SIGNATURES;
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitExplodeJsonObject(this, context);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/ExplodeJsonObjectOuter.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/ExplodeJsonObjectOuter.java
new file mode 100644
index 00000000000..7f927c90e9d
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/ExplodeJsonObjectOuter.java
@@ -0,0 +1,68 @@
+// 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.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.JsonType;
+import org.apache.doris.nereids.types.StringType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * explode_json_object_out is explode_json_object without null value.
+ */
+public class ExplodeJsonObjectOuter extends TableGeneratingFunction implements 
UnaryExpression, AlwaysNullable {
+
+    public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+            FunctionSignature.ret(StructLiteral.constructStructType(
+                    ImmutableList.of(StringType.INSTANCE, 
JsonType.INSTANCE))).args(JsonType.INSTANCE));
+
+    /**
+     * constructor with 1 argument.
+     */
+    public ExplodeJsonObjectOuter(Expression arg) {
+        super("explode_json_object_outer", arg);
+    }
+
+    /**
+     * withChildren.
+     */
+    @Override
+    public ExplodeJsonObjectOuter withChildren(List<Expression> children) {
+        Preconditions.checkArgument(children.size() == 1);
+        return new ExplodeJsonObjectOuter(children.get(0));
+    }
+
+    @Override
+    public List<FunctionSignature> getSignatures() {
+        return SIGNATURES;
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitExplodeJsonObjectOuter(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 4e4c8ab2bd4..f66d72f6409 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
@@ -28,6 +28,8 @@ import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJso
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonArrayJsonOuter;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonArrayString;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonArrayStringOuter;
+import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonObject;
+import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeJsonObjectOuter;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeMap;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeMapOuter;
 import 
org.apache.doris.nereids.trees.expressions.functions.generator.ExplodeNumbers;
@@ -59,6 +61,14 @@ public interface TableGeneratingFunctionVisitor<R, C> {
         return visitTableGeneratingFunction(explodeOuter, context);
     }
 
+    default R visitExplodeJsonObject(ExplodeJsonObject explode, C context) {
+        return visitTableGeneratingFunction(explode, context);
+    }
+
+    default R visitExplodeJsonObjectOuter(ExplodeJsonObjectOuter explodeOuter, 
C context) {
+        return visitTableGeneratingFunction(explodeOuter, context);
+    }
+
     default R visitExplodeNumbers(ExplodeNumbers explodeNumbers, C context) {
         return visitTableGeneratingFunction(explodeNumbers, context);
     }
diff --git 
a/regression-test/data/nereids_p0/jsonb_p0/test_jsonb_load_and_function.out 
b/regression-test/data/nereids_p0/jsonb_p0/test_jsonb_load_and_function.out
index 80a3880a549..0d33127ad20 100644
--- a/regression-test/data/nereids_p0/jsonb_p0/test_jsonb_load_and_function.out
+++ b/regression-test/data/nereids_p0/jsonb_p0/test_jsonb_load_and_function.out
@@ -8315,6 +8315,82 @@ false
 33     {"":1,"":"v1"}  [null,null,null]
 34     {"":1,"ab":"v1","":"v1","":2}   [null,null,null]
 
+-- !order_select_explode_json_object --
+1      \N      \N      \N
+2      null    \N      \N
+3      true    \N      \N
+4      false   \N      \N
+5      100     \N      \N
+6      10000   \N      \N
+7      1000000000      \N      \N
+8      1152921504606846976     \N      \N
+9      6.18    \N      \N
+10     "abcd"  \N      \N
+11     {}      \N      \N
+12     {"k1":"v31","k2":300}   k1      "v31"
+12     {"k1":"v31","k2":300}   k2      300
+13     []      \N      \N
+14     [123,456]       \N      \N
+15     ["abc","def"]   \N      \N
+16     [null,true,false,100,6.18,"abc"]        \N      \N
+17     [{"k1":"v41","k2":400},1,"a",3.14]      \N      \N
+18     {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]}   a1      
[{"k1":"v41","k2":400},1,"a",3.14]
+18     {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]}   k1      
"v31"
+18     {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]}   k2      
300
+26     \N      \N      \N
+27     {"k1":"v1","k2":200}    k1      "v1"
+27     {"k1":"v1","k2":200}    k2      200
+28     {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"}    a       "niu"
+28     {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"}    a.b.c   
{"k1.a1":"v31","k2":300}
+29     12524337771678448270    \N      \N
+30     -9223372036854775808    \N      \N
+31     18446744073709551615    \N      \N
+32     {"":"v1"}               "v1"
+33     {"":1,"":"v1"}          1
+33     {"":1,"":"v1"}          "v1"
+34     {"":1,"ab":"v1","":"v1","":2}           1
+34     {"":1,"ab":"v1","":"v1","":2}           "v1"
+34     {"":1,"ab":"v1","":"v1","":2}           2
+34     {"":1,"ab":"v1","":"v1","":2}   ab      "v1"
+
+-- !order_select_explode_json_object_out --
+1      \N      \N      \N
+2      null    \N      \N
+3      true    \N      \N
+4      false   \N      \N
+5      100     \N      \N
+6      10000   \N      \N
+7      1000000000      \N      \N
+8      1152921504606846976     \N      \N
+9      6.18    \N      \N
+10     "abcd"  \N      \N
+11     {}      \N      \N
+12     {"k1":"v31","k2":300}   k1      "v31"
+12     {"k1":"v31","k2":300}   k2      300
+13     []      \N      \N
+14     [123,456]       \N      \N
+15     ["abc","def"]   \N      \N
+16     [null,true,false,100,6.18,"abc"]        \N      \N
+17     [{"k1":"v41","k2":400},1,"a",3.14]      \N      \N
+18     {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]}   a1      
[{"k1":"v41","k2":400},1,"a",3.14]
+18     {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]}   k1      
"v31"
+18     {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]}   k2      
300
+26     \N      \N      \N
+27     {"k1":"v1","k2":200}    k1      "v1"
+27     {"k1":"v1","k2":200}    k2      200
+28     {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"}    a       "niu"
+28     {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"}    a.b.c   
{"k1.a1":"v31","k2":300}
+29     12524337771678448270    \N      \N
+30     -9223372036854775808    \N      \N
+31     18446744073709551615    \N      \N
+32     {"":"v1"}               "v1"
+33     {"":1,"":"v1"}          1
+33     {"":1,"":"v1"}          "v1"
+34     {"":1,"ab":"v1","":"v1","":2}           1
+34     {"":1,"ab":"v1","":"v1","":2}           "v1"
+34     {"":1,"ab":"v1","":"v1","":2}           2
+34     {"":1,"ab":"v1","":"v1","":2}   ab      "v1"
+
 -- !sql_json_parse --
 {"":"v1"}
 
@@ -8322,5 +8398,4 @@ false
 {"":1,"":"v1"}
 
 -- !sql_json_parse --
-{"":1,"ab":"v1","":"v1","":2}
-
+{"":1,"ab":"v1","":"v1","":2}
\ No newline at end of file
diff --git 
a/regression-test/suites/jsonb_p0/test_jsonb_load_and_function.groovy 
b/regression-test/suites/jsonb_p0/test_jsonb_load_and_function.groovy
index f8ce6aa2f63..00740d88a62 100644
--- a/regression-test/suites/jsonb_p0/test_jsonb_load_and_function.groovy
+++ b/regression-test/suites/jsonb_p0/test_jsonb_load_and_function.groovy
@@ -579,6 +579,15 @@ suite("test_jsonb_load_and_function", "p0") {
     qt_select_json_contains """SELECT id, j, json_contains(j, 
cast('{"k1":"v41","k2":400}' as json), '\$.a1') FROM ${testTable} ORDER BY id"""
     qt_select_json_contains """SELECT id, j, json_contains(j, cast('[123,456]' 
as json)) FROM ${testTable} ORDER BY id"""
 
+    // old planner do not support explode_json_object
+    test {
+        sql """ select /*+SET_VAR(experimental_enable_nereids_planner=false)*/ 
id, j, k,v from ${testTable} lateral view explode_json_object_outer(j) tmp as 
k,v order by id; """
+        exception "errCode = 2"
+    }
+    test {
+        sql """ select /*+SET_VAR(experimental_enable_nereids_planner=false)*/ 
id, j, k,v from ${testTable} lateral view explode_json_object_outer(j) tmp as 
k,v order by id; """
+        exception "errCode = 2"
+    }
     // json_parse
     qt_sql_json_parse """SELECT/*+SET_VAR(enable_fold_constant_by_be=false)*/ 
json_parse('{"":"v1"}')"""
     qt_sql_json_parse """SELECT/*+SET_VAR(enable_fold_constant_by_be=false)*/ 
json_parse('{"":1, "":"v1"}')"""
diff --git 
a/regression-test/suites/nereids_p0/jsonb_p0/test_jsonb_load_and_function.groovy
 
b/regression-test/suites/nereids_p0/jsonb_p0/test_jsonb_load_and_function.groovy
index d4baa081c4c..d44e81f8fa5 100644
--- 
a/regression-test/suites/nereids_p0/jsonb_p0/test_jsonb_load_and_function.groovy
+++ 
b/regression-test/suites/nereids_p0/jsonb_p0/test_jsonb_load_and_function.groovy
@@ -543,6 +543,10 @@ suite("test_jsonb_load_and_function", "p0") {
     qt_select """SELECT id, j, JSON_EXTRACT(j, '\$.k2', null) FROM 
${testTable} ORDER BY id"""
     qt_select """SELECT id, j, JSON_EXTRACT(j, '\$.a1[0].k1', '\$.a1[0].k2', 
'\$.a1[2]') FROM ${testTable} ORDER BY id"""
 
+    // explode_json_object function
+    order_qt_order_select_explode_json_object "select id, j, k,v from 
${testTable} lateral view explode_json_object(j) tmp as k,v order by id, k;"
+    order_qt_order_select_explode_json_object_out "select id, j, k,v from 
${testTable} lateral view explode_json_object_outer(j) tmp as k,v order by id, 
k;"
+
     // json_parse
     qt_sql_json_parse """SELECT/*+SET_VAR(enable_fold_constant_by_be=false)*/ 
json_parse('{"":"v1"}')"""
     qt_sql_json_parse """SELECT/*+SET_VAR(enable_fold_constant_by_be=false)*/ 
json_parse('{"":1, "":"v1"}')"""


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to