This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.0 by this push:
new 4764b459a48 [branch-4.0](jsonb) add json_object_flatten scalar
function (#62825) (#63114)
4764b459a48 is described below
commit 4764b459a4890d94a24f98d0facabed3b56d81d6
Author: Chenyang Sun <[email protected]>
AuthorDate: Thu May 28 10:23:01 2026 +0800
[branch-4.0](jsonb) add json_object_flatten scalar function (#62825)
(#63114)
pick from master #62825
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
be/src/vec/functions/function_jsonb_transform.cpp | 54 ++++++++
.../function/function_json_object_flatten_test.cpp | 136 +++++++++++++++++++++
.../doris/catalog/BuiltinScalarFunctions.java | 2 +
.../functions/scalar/JsonObjectFlatten.java | 70 +++++++++++
.../expressions/visitor/ScalarFunctionVisitor.java | 5 +
.../data/variant_p0/test_json_object_flatten.out | 39 ++++++
.../variant_p0/test_json_object_flatten.groovy | 84 +++++++++++++
7 files changed, 390 insertions(+)
diff --git a/be/src/vec/functions/function_jsonb_transform.cpp
b/be/src/vec/functions/function_jsonb_transform.cpp
index d57ad314bc9..7d0eaaa59ed 100644
--- a/be/src/vec/functions/function_jsonb_transform.cpp
+++ b/be/src/vec/functions/function_jsonb_transform.cpp
@@ -15,6 +15,7 @@
// specific language governing permissions and limitations
// under the License.
+#include <string>
#include <vector>
#include "runtime/primitive_type.h"
@@ -62,6 +63,50 @@ void sort_json_object_keys(JsonbWriter& jsonb_writer, const
JsonbValue* jsonb_va
}
}
+// Walk a JSONB object recursively and emit flat "<dot.path>": value entries
+// directly into `writer`. Members whose value is a non-empty object recurse;
+// every other shape (scalars, arrays, null literals, empty objects) is emitted
+// as an opaque leaf at its dot-joined path. The `prefix` buffer is reused
+// across the whole row — appended on descent and truncated on return — so no
+// path segment is ever re-allocated outside this single growing string.
+void flatten_json_object_into(JsonbWriter& jsonb_writer, const ObjectVal* obj,
+ std::string& prefix) {
+ for (auto it = obj->begin(); it != obj->end(); ++it) {
+ const auto* val = it->value();
+ const size_t saved = prefix.size();
+ if (!prefix.empty()) {
+ prefix.push_back('.');
+ }
+ prefix.append(it->getKeyStr(), it->klen());
+
+ if (val->isObject() && val->unpack<ObjectVal>()->numElem() > 0) {
+ flatten_json_object_into(jsonb_writer, val->unpack<ObjectVal>(),
prefix);
+ } else {
+ jsonb_writer.writeKey(prefix.data(),
static_cast<uint8_t>(prefix.size()));
+ jsonb_writer.writeValue(val);
+ }
+ prefix.resize(saved);
+ }
+}
+
+// json_object_flatten: turn a nested JSONB object into a single-level JSONB
+// object whose keys are the dot-joined paths to each leaf (NiFi FlattenJson
+// "keep-arrays" semantics — arrays / scalars / nulls / empty objects stay as
+// opaque leaf values; only objects are walked).
+// {"a":{"b":2}} -> {"a.b":2}
+// {"a":[{"b":1}]} -> {"a":[{"b":1}]}
+// Top-level non-object values pass through unchanged.
+void flatten_json_object(JsonbWriter& jsonb_writer, const JsonbValue*
jsonb_value) {
+ if (!jsonb_value->isObject()) {
+ jsonb_writer.writeValue(jsonb_value);
+ return;
+ }
+ jsonb_writer.writeStartObject();
+ std::string prefix;
+ flatten_json_object_into(jsonb_writer, jsonb_value->unpack<ObjectVal>(),
prefix);
+ jsonb_writer.writeEndObject();
+}
+
// Convert all numeric types in JSON to double type
void normalize_json_numbers_to_double(JsonbWriter& jsonb_writer, const
JsonbValue* jsonb_value) {
if (jsonb_value->isObject()) {
@@ -167,12 +212,21 @@ struct NormalizeJsonNumbersToDouble {
}
};
+struct JsonObjectFlatten {
+ static constexpr auto name = "json_object_flatten";
+ static void transform(JsonbWriter& writer, const JsonbValue* value) {
+ flatten_json_object(writer, value);
+ }
+};
+
using FunctionSortJsonObjectKeys = FunctionJsonbTransform<SortJsonObjectKeys>;
using FunctionNormalizeJsonNumbersToDouble =
FunctionJsonbTransform<NormalizeJsonNumbersToDouble>;
+using FunctionJsonObjectFlatten = FunctionJsonbTransform<JsonObjectFlatten>;
void register_function_json_transform(SimpleFunctionFactory& factory) {
factory.register_function<FunctionSortJsonObjectKeys>();
factory.register_function<FunctionNormalizeJsonNumbersToDouble>();
+ factory.register_function<FunctionJsonObjectFlatten>();
factory.register_alias(FunctionSortJsonObjectKeys::name,
"sort_jsonb_object_keys");
factory.register_alias(FunctionNormalizeJsonNumbersToDouble::name,
diff --git a/be/test/vec/function/function_json_object_flatten_test.cpp
b/be/test/vec/function/function_json_object_flatten_test.cpp
new file mode 100644
index 00000000000..927e0917ae6
--- /dev/null
+++ b/be/test/vec/function/function_json_object_flatten_test.cpp
@@ -0,0 +1,136 @@
+// 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 <gtest/gtest.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "util/jsonb_document.h"
+#include "util/jsonb_parser_simd.h"
+#include "util/jsonb_utils.h"
+#include "util/jsonb_writer.h"
+#include "vec/functions/function_jsonb_transform.cpp"
+
+namespace doris {
+
+using vectorized::flatten_json_object;
+
+namespace {
+
+// Parse JSON text into JSONB bytes via the standard simdjson-backed parser.
+std::string json_to_jsonb(const std::string& json) {
+ JsonbWriter writer;
+ auto status = JsonbParser::parse(json.data(), json.size(), writer);
+ EXPECT_TRUE(status.ok()) << "parse failed: " << json << " -> " <<
status.to_string();
+ return std::string(writer.getOutput()->getBuffer(),
writer.getOutput()->getSize());
+}
+
+// Run flatten_json_object end-to-end starting from a JSON text input and
+// returning the flattened result rendered back to JSON text. The parse →
+// flatten → re-render trip exercises the same code path the SQL function
+// follows: ColumnString(JSONB) -> flatten_json_object -> ColumnString(JSONB).
+std::string flatten(const std::string& json_in) {
+ const std::string in_bytes = json_to_jsonb(json_in);
+ const JsonbDocument* doc = nullptr;
+ auto status = JsonbDocument::checkAndCreateDocument(in_bytes.data(),
in_bytes.size(), &doc);
+ EXPECT_TRUE(status.ok()) << status.to_string();
+ EXPECT_NE(doc, nullptr);
+
+ JsonbWriter writer;
+ flatten_json_object(writer, doc->getValue());
+ return JsonbToJson::jsonb_to_json_string(writer.getOutput()->getBuffer(),
+ writer.getOutput()->getSize());
+}
+
+void check(const std::string& input, const std::string& expected) {
+ EXPECT_EQ(flatten(input), expected) << "input: " << input;
+}
+
+} // namespace
+
+TEST(function_json_object_flatten_test, two_level) {
+ check(R"({"a":{"b":2}})", R"({"a.b":2})");
+}
+
+TEST(function_json_object_flatten_test, three_level) {
+ check(R"({"a":{"b":{"c":3}}})", R"({"a.b.c":3})");
+}
+
+TEST(function_json_object_flatten_test, already_flat) {
+ check(R"({"a":1,"b":"hi"})", R"({"a":1,"b":"hi"})");
+}
+
+TEST(function_json_object_flatten_test, empty_top_level_object) {
+ check("{}", "{}");
+}
+
+TEST(function_json_object_flatten_test, empty_nested_object_is_leaf) {
+ check(R"({"a":{}})", R"({"a":{}})");
+}
+
+TEST(function_json_object_flatten_test, deep_nesting) {
+
check(R"({"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":{"i":{"j":{"k":1}}}}}}}}}}})",
+ R"({"a.b.c.d.e.f.g.h.i.j.k":1})");
+}
+
+TEST(function_json_object_flatten_test,
prefix_buffer_is_reset_across_siblings) {
+ check(R"({"a":{"x":1},"b":{"y":2}})", R"({"a.x":1,"b.y":2})");
+}
+
+TEST(function_json_object_flatten_test,
array_of_scalars_under_nested_path_stays_opaque) {
+ check(R"({"a":{"b":[1,2,3]}})", R"({"a.b":[1,2,3]})");
+}
+
+TEST(function_json_object_flatten_test,
array_of_objects_under_nested_path_stays_opaque) {
+ // keep-arrays semantics: the array is a leaf value under "a.b"; the
+ // inner object's key "d" must NOT show up at the flat level.
+ check(R"({"a":{"b":[{"d":1},{"d":2}]}})", R"({"a.b":[{"d":1},{"d":2}]})");
+}
+
+TEST(function_json_object_flatten_test, mixed_object_scalar_and_array_leaves) {
+ check(R"({"x":{"s":1,"a":[1,2],"o":{"k":"v"}}})",
R"({"x.s":1,"x.a":[1,2],"x.o.k":"v"})");
+}
+
+TEST(function_json_object_flatten_test, null_leaf_at_top) {
+ check(R"({"a":null})", R"({"a":null})");
+}
+
+TEST(function_json_object_flatten_test, null_leaf_nested) {
+ check(R"({"a":{"b":null}})", R"({"a.b":null})");
+}
+
+TEST(function_json_object_flatten_test, top_level_scalar_pass_through) {
+ check("42", "42");
+ check("\"hello\"", "\"hello\"");
+ check("null", "null");
+ check("true", "true");
+}
+
+TEST(function_json_object_flatten_test, top_level_array_pass_through) {
+ check(R"([1,2,3])", R"([1,2,3])");
+ check(R"([{"x":1}])", R"([{"x":1}])");
+}
+
+TEST(function_json_object_flatten_test, literal_dotted_key_round_trips) {
+ // A literal '.' inside a key collapses with real nesting at the flat layer
+ // — the same documented-lossy collision NiFi FlattenJson accepts.
+ check(R"({"a.b":2})", R"({"a.b":2})");
+}
+
+} // namespace doris
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
index 99c6b770168..8ad180af9c2 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
@@ -286,6 +286,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.JsonInsert;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonKeys;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonLength;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonObject;
+import
org.apache.doris.nereids.trees.expressions.functions.scalar.JsonObjectFlatten;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonQuote;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonRemove;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonReplace;
@@ -842,6 +843,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(JsonArray.class, "json_array", "jsonb_array"),
scalar(JsonArrayIgnoreNull.class, "json_array_ignore_null",
"jsonb_array_ignore_null"),
scalar(JsonObject.class, "json_object", "jsonb_object"),
+ scalar(JsonObjectFlatten.class, "json_object_flatten"),
scalar(JsonQuote.class, "json_quote"),
scalar(JsonUnQuote.class, "json_unquote"),
scalar(JsonExtractNoQuotes.class, "json_extract_no_quotes"),
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonObjectFlatten.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonObjectFlatten.java
new file mode 100644
index 00000000000..d7ddd09ae09
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonObjectFlatten.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.scalar;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+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.JsonType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'json_object_flatten'. Turn a nested JSONB object into a
+ * single-level JSONB object whose keys are dot-joined paths to each leaf
+ * (NiFi FlattenJson "keep-arrays" semantics — arrays stay as opaque values):
+ * {"a":{"b":2}} -> {"a.b":2}
+ * {"a":[{"b":1}]} -> {"a":[{"b":1}]}
+ * To flatten a VARIANT, wrap it with `to_json`:
json_object_flatten(to_json(v)).
+ */
+public class JsonObjectFlatten extends ScalarFunction
+ implements UnaryExpression, ExplicitlyCastableSignature,
PropagateNullable {
+
+ public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(JsonType.INSTANCE).args(JsonType.INSTANCE));
+
+ public JsonObjectFlatten(Expression arg0) {
+ super("json_object_flatten", arg0);
+ }
+
+ private JsonObjectFlatten(ScalarFunctionParams functionParams) {
+ super(functionParams);
+ }
+
+ @Override
+ public JsonObjectFlatten withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 1);
+ return new JsonObjectFlatten(getFunctionParams(children));
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return SIGNATURES;
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitJsonObjectFlatten(this, context);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
index 520e6193f3f..2edfc133152 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
@@ -305,6 +305,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.JsonInsert;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonKeys;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonLength;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonObject;
+import
org.apache.doris.nereids.trees.expressions.functions.scalar.JsonObjectFlatten;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonQuote;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonRemove;
import org.apache.doris.nereids.trees.expressions.functions.scalar.JsonReplace;
@@ -1710,6 +1711,10 @@ public interface ScalarFunctionVisitor<R, C> {
return visitScalarFunction(jsonObject, context);
}
+ default R visitJsonObjectFlatten(JsonObjectFlatten jsonObjectFlatten, C
context) {
+ return visitScalarFunction(jsonObjectFlatten, context);
+ }
+
default R visitJsonExtractNoQuotes(JsonExtractNoQuotes jsonExtract, C
context) {
return visitScalarFunction(jsonExtract, context);
}
diff --git a/regression-test/data/variant_p0/test_json_object_flatten.out
b/regression-test/data/variant_p0/test_json_object_flatten.out
new file mode 100644
index 00000000000..39673a715ac
--- /dev/null
+++ b/regression-test/data/variant_p0/test_json_object_flatten.out
@@ -0,0 +1,39 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !sql_jsonb --
+1 {"a.b":2}
+2 {"a.b.c":3}
+3 {"a":1,"b":"hi"}
+4 {}
+5 {"a":{}}
+6 {"a":null}
+7 {"a.b":null}
+8 {"a.b.c.d.e.f.g.h.i.j.k.l":1}
+9 \N
+10 42
+11 "hello"
+12 {"a":[1,2,3]}
+13 {"a":[{"b":1},{"b":2}]}
+14 {"a.b":[1,2,3]}
+15 {"a.b":[{"c":1},{"c":2}]}
+16 [1,2,{"x":3}]
+17 {"x.s":1,"x.a":[1,2],"x.o.k":"v"}
+
+-- !sql_variant --
+1 {"a.b":2}
+2 {"a.b.c":3}
+3 {"a":1,"b":"hi"}
+4 \N
+5 \N
+6 \N
+7 \N
+8 {"a.b.c.d.e.f.g.h.i.j.k.l":1}
+9 \N
+10 42
+11 "hello"
+12 {"a":[1,2,3]}
+13 {"a":[{"b":1},{"b":2}]}
+14 {"a.b":[1,2,3]}
+15 {"a.b":[{"c":1},{"c":2}]}
+16 [1,2,{"x":3}]
+17 {"x.a":[1,2],"x.o.k":"v","x.s":1}
+
diff --git a/regression-test/suites/variant_p0/test_json_object_flatten.groovy
b/regression-test/suites/variant_p0/test_json_object_flatten.groovy
new file mode 100644
index 00000000000..02784d0dff1
--- /dev/null
+++ b/regression-test/suites/variant_p0/test_json_object_flatten.groovy
@@ -0,0 +1,84 @@
+// 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("regression_test_json_object_flatten", "p0") {
+ // 1) JSONB column: function takes JSONB directly.
+ sql """DROP TABLE IF EXISTS json_object_flatten_jsonb_t"""
+ sql """
+ CREATE TABLE json_object_flatten_jsonb_t (
+ k bigint,
+ j jsonb
+ )
+ DUPLICATE KEY(k)
+ DISTRIBUTED BY HASH(k) BUCKETS 1
+ PROPERTIES ("replication_num" = "1", "disable_auto_compaction" =
"true");
+ """
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (1, '{"a": {"b":
2}}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (2, '{"a": {"b":
{"c": 3}}}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (3, '{"a": 1, "b":
"hi"}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (4, '{}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (5, '{"a": {}}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (6, '{"a": null}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (7, '{"a": {"b":
null}}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (8,
'{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":{"i":{"j":{"k":{"l":1}}}}}}}}}}}}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (9, NULL)"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (10, '42')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (11, '"hello"')"""
+ // Array-leaf cases: keep-arrays semantics — the array stays opaque at
+ // its dot-path; element-level keys must NOT leak into the flat output.
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (12, '{"a": [1, 2,
3]}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (13, '{"a": [{"b":
1}, {"b": 2}]}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (14, '{"a": {"b":
[1, 2, 3]}}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (15, '{"a": {"b":
[{"c": 1}, {"c": 2}]}}')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (16, '[1, 2, {"x":
3}]')"""
+ sql """INSERT INTO json_object_flatten_jsonb_t VALUES (17, '{"x": {"s": 1,
"a": [1, 2], "o": {"k": "v"}}}')"""
+
+ qt_sql_jsonb """SELECT k, json_object_flatten(j) FROM
json_object_flatten_jsonb_t ORDER BY k"""
+
+ // 2) VARIANT column: Nereids inserts an implicit Variant -> JSONB cast,
+ // so users can pass the variant column straight to json_object_flatten.
+ sql """DROP TABLE IF EXISTS json_object_flatten_variant_t"""
+ sql """
+ CREATE TABLE json_object_flatten_variant_t (
+ k bigint,
+ v variant
+ )
+ DUPLICATE KEY(k)
+ DISTRIBUTED BY HASH(k) BUCKETS 1
+ PROPERTIES ("replication_num" = "1", "disable_auto_compaction" =
"true");
+ """
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (1, '{"a": {"b":
2}}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (2, '{"a": {"b":
{"c": 3}}}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (3, '{"a": 1, "b":
"hi"}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (4, '{}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (5, '{"a": {}}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (6, '{"a":
null}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (7, '{"a": {"b":
null}}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (8,
'{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":{"i":{"j":{"k":{"l":1}}}}}}}}}}}}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (9, NULL)"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (10, '42')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (11, '"hello"')"""
+ // Array-leaf cases through the variant -> jsonb cast path.
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (12, '{"a": [1, 2,
3]}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (13, '{"a": [{"b":
1}, {"b": 2}]}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (14, '{"a": {"b":
[1, 2, 3]}}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (15, '{"a": {"b":
[{"c": 1}, {"c": 2}]}}')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (16, '[1, 2, {"x":
3}]')"""
+ sql """INSERT INTO json_object_flatten_variant_t VALUES (17, '{"x": {"s":
1, "a": [1, 2], "o": {"k": "v"}}}')"""
+
+ qt_sql_variant """SELECT k, json_object_flatten(v) FROM
json_object_flatten_variant_t ORDER BY k"""
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]