From 3cb1d4e842a4824b2ff4707f9bf76277233fa162 Mon Sep 17 00:00:00 2001 From: amory Date: Tue, 16 Jul 2024 10:59:11 +0800 Subject: [PATCH] [feature](json)support explode_json_object func #36887 (#37378) --- .../vec/exprs/table_function/table_function.h | 1 + .../exprs/table_function/vexplode_bitmap.cpp | 2 +- .../table_function/vexplode_json_array.h | 2 +- .../table_function/vexplode_json_object.cpp | 160 ++++++++++++++++++ .../table_function/vexplode_json_object.h | 59 +++++++ be/src/vec/functions/function_fake.cpp | 14 ++ .../BuiltinTableGeneratingFunctions.java | 4 + .../generator/ExplodeJsonObject.java | 70 ++++++++ .../generator/ExplodeJsonObjectOuter.java | 68 ++++++++ .../TableGeneratingFunctionVisitor.java | 10 ++ .../jsonb_p0/test_jsonb_load_and_function.out | 79 ++++++++- .../test_jsonb_load_and_function.groovy | 9 + .../test_jsonb_load_and_function.groovy | 4 + 13 files changed, 478 insertions(+), 4 deletions(-) create mode 100644 be/src/vec/exprs/table_function/vexplode_json_object.cpp create mode 100644 be/src/vec/exprs/table_function/vexplode_json_object.h create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/ExplodeJsonObject.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/generator/ExplodeJsonObjectOuter.java diff --git a/be/src/vec/exprs/table_function/table_function.h b/be/src/vec/exprs/table_function/table_function.h index bd926c3657..fc3d3882b5 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 5327c2e163..e6e4c84307 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 968fa5e91a..1d89d9fa57 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 0000000000..1981f48f62 --- /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 + +#include +#include + +#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(); + 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( + assert_cast(column.get())->get_nested_column_ptr().get()); + assert_cast( + assert_cast(column.get())->get_null_map_column_ptr().get()) + ->insert_many_defaults(length); + } else if (column->is_column_struct()) { + ret = assert_cast(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(column.get()); + struct_column = + assert_cast(nullable_column->get_nested_column_ptr().get()); + auto* nullmap_column = + assert_cast(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(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 0000000000..9173fd9cba --- /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 + +#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 _object_pairs; // ColumnNullable +}; + +} // namespace doris::vectorized diff --git a/be/src/vec/functions/function_fake.cpp b/be/src/vec/functions/function_fake.cpp index 2d8e258d52..0353b3a2a7 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()); + fieldTypes[1] = make_nullable(std::make_shared()); + return make_nullable(std::make_shared(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::get_return_type_impl(arguments); @@ -113,6 +126,7 @@ void register_function_fake(SimpleFunctionFactory& factory) { register_table_function_expand_outer(factory, "explode"); register_table_function_expand_outer(factory, "explode_map"); + register_table_function_expand_outer(factory, "explode_json_object"); 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"); 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 6fab5cfc04..84894db95c 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 0000000000..e4546205b7 --- /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 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 children) { + Preconditions.checkArgument(children.size() == 1); + return new ExplodeJsonObject(children.get(0)); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } + + @Override + public R accept(ExpressionVisitor 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 0000000000..7f927c90e9 --- /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 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 children) { + Preconditions.checkArgument(children.size() == 1); + return new ExplodeJsonObjectOuter(children.get(0)); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } + + @Override + public R accept(ExpressionVisitor 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 4e4c8ab2bd..f66d72f640 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 { 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 80a3880a54..0d33127ad2 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 f8ce6aa2f6..00740d88a6 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 d4baa081c4..d44e81f8fa 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"}')"""