This is an automated email from the ASF dual-hosted git repository.
yiguolei 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 e2405875cf6 [chore](be) Remove unused V1 JSONDataParser (#68232)
e2405875cf6 is described below
commit e2405875cf66abdb99d4f2b6520f9a704023b61d
Author: lihangyu <[email protected]>
AuthorDate: Mon Sep 21 10:15:38 2026 +0800
[chore](be) Remove unused V1 JSONDataParser (#68232)
### What problem does this PR solve?
Issue Number: None
Related PR: #66858
Problem Summary: After #66858 enabled Variant V2 by default, the V1 JSON
parser in `be/src/util/json/json_parser.{h,cpp}` (`JSONDataParser`,
`ParseConfig`, `ParseResult` and the
`getValueAsField`/`writeValueAsJsonb` helpers) has no production caller;
only tests still referenced it.
This PR removes:
- the parser itself (`be/src/util/json/json_parser.{h,cpp}`), including
its `extern template class JSONDataParser<SimdJSONParser>` declaration
and the matching explicit instantiation;
- its dedicated test `be/test/core/jsonb/json_parser_test.cpp`, which
covered nothing else;
- the stale `#include "util/json/json_parser.h"` lines left in
`segment_creator.cpp`, `function_variant_parse.cpp`, `variant_util.cpp`,
`cast_to_decimal128_perf.cpp` and `index_storage_test_util.h`;
- the never-read `IndexBatch::parse_to` test field (of type
`ParseConfig::ParseTo`) and its single assignment in
`index_storage_variant_debug_point_test.cpp`.
`be/test/util/variant/variant_field_test.cpp` contained one case
comparing the V1 parser against the V2 encoder; only its V2
`encode_json` assertions are kept, renamed to
`VariantFieldTest.EncodeJsonStableSubset`.
`util/json/simd_json_parser.h` and `util/json/path_in_data.{h,cpp}` are
kept, as both still have production users.
Note: `be/benchmark/benchmark_variant_segment.hpp` also references
`ParseConfig`, but its V1 branch already fails to compile on master (it
calls `ColumnVariant`, `variant_util::parse_json_to_variant` and
`variant_util::select_storage_variant_parse_target`, none of which exist
any more). It is built only with the BE benchmark target and is left for
a separate fix.
### Release note
None
### Check List (For Author)
- Test: Unit Test
- `build-support/check-build-hygiene.sh` passed
- ASAN BE build (`./build.sh --be`) passed
- `./run-be-ut.sh --run --filter='VariantFieldTest.*:IndexStorage*'`
passed: 83 passed, 2 pre-existing skips
- Behavior changed: No
- Does this need documentation: No
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 <[email protected]>
---
be/src/exec/common/variant_util.cpp | 1 -
be/src/exprs/function/function_variant_parse.cpp | 1 -
be/src/storage/rowset/segment_creator.cpp | 1 -
be/src/util/json/json_parser.cpp | 414 ------------------
be/src/util/json/json_parser.h | 179 --------
be/test/core/jsonb/json_parser_test.cpp | 481 ---------------------
.../function/cast/cast_to_decimal128_perf.cpp | 1 -
.../index_storage_variant_debug_point_test.cpp | 1 -
be/test/testutil/index_storage_test_util.h | 2 -
be/test/util/variant/variant_field_test.cpp | 41 +-
10 files changed, 3 insertions(+), 1119 deletions(-)
diff --git a/be/src/exec/common/variant_util.cpp
b/be/src/exec/common/variant_util.cpp
index e2b46cbe47d..61c6f5b0a71 100644
--- a/be/src/exec/common/variant_util.cpp
+++ b/be/src/exec/common/variant_util.cpp
@@ -97,7 +97,6 @@
#include "storage/tablet/tablet_schema.h"
#include "util/client_cache.h"
#include "util/defer_op.h"
-#include "util/json/json_parser.h"
#include "util/json/path_in_data.h"
#include "util/json/simd_json_parser.h"
#include "util/jsonb_utils.h"
diff --git a/be/src/exprs/function/function_variant_parse.cpp
b/be/src/exprs/function/function_variant_parse.cpp
index c931cb1738c..2f4dcf69cf7 100644
--- a/be/src/exprs/function/function_variant_parse.cpp
+++ b/be/src/exprs/function/function_variant_parse.cpp
@@ -29,7 +29,6 @@
#include "core/data_type/data_type_variant_v2.h"
#include "exprs/function/parse/variant_string_parse.h"
#include "exprs/function/simple_function_factory.h"
-#include "util/json/json_parser.h"
namespace doris {
namespace {
diff --git a/be/src/storage/rowset/segment_creator.cpp
b/be/src/storage/rowset/segment_creator.cpp
index bcdbea7c7fe..85ccb0aa957 100644
--- a/be/src/storage/rowset/segment_creator.cpp
+++ b/be/src/storage/rowset/segment_creator.cpp
@@ -49,7 +49,6 @@
#include "storage/transform/block_transform.h"
#include "storage/utils.h"
#include "util/debug_points.h"
-#include "util/json/json_parser.h"
#include "util/pretty_printer.h"
#include "util/stopwatch.hpp"
diff --git a/be/src/util/json/json_parser.cpp b/be/src/util/json/json_parser.cpp
deleted file mode 100644
index 3df723c3849..00000000000
--- a/be/src/util/json/json_parser.cpp
+++ /dev/null
@@ -1,414 +0,0 @@
-// 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.
-// This file is copied from
-//
https://github.com/ClickHouse/ClickHouse/blob/master/src/Common/JSONParsers/SimdJSONParser.cpp
-// and modified by Doris
-
-#include "util/json/json_parser.h"
-
-#include <fmt/format.h>
-#include <glog/logging.h>
-
-#include <algorithm>
-#include <cassert>
-#include <string_view>
-#include <vector>
-
-#include "common/cast_set.h"
-// IWYU pragma: keep
-#include "common/status.h"
-#include "util/json/path_in_data.h"
-#include "util/json/simd_json_parser.h"
-
-namespace doris {
-
-template <typename ParserImpl>
-std::optional<ParseResult> JSONDataParser<ParserImpl>::parse(const char*
begin, size_t length,
- const
ParseConfig& config) {
- Element document;
- if (!parser.parse(begin, length, document)) {
- return {};
- }
- ParseContext context;
- // deprecated_enable_flatten_nested controls nested path traversal
- // NestedGroup expansion is now handled at storage layer
- context.deprecated_enable_flatten_nested =
config.deprecated_enable_flatten_nested;
- context.check_duplicate_json_path = config.check_duplicate_json_path;
- context.is_top_array = document.isArray();
- traverse(document, context);
- ParseResult result;
- result.values = std::move(context.values);
- result.paths.reserve(context.paths.size());
- for (auto&& path : context.paths) {
- result.paths.emplace_back(std::move(path));
- }
- return result;
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::traverse(const Element& element,
ParseContext& ctx) {
- // checkStackSize();
- if (element.isObject()) {
- traverseObject(element.getObject(), ctx);
- } else if (element.isArray()) {
- // allow nested arrays (multi-level) for NestedGroup; deeper levels are
- // handled by VariantNestedBuilder with a max-depth guard.
- has_nested = false;
- check_has_nested_object(element);
- ctx.has_nested_in_flatten = has_nested &&
ctx.deprecated_enable_flatten_nested;
- if (has_nested && !ctx.deprecated_enable_flatten_nested) {
- // Parse nested arrays to JsonbField
- JsonbWriter writer;
- traverseArrayAsJsonb(element.getArray(), writer);
- appendValueIfNotDuplicate(
- ctx, ctx.builder.get_parts(),
-
Field::create_field<TYPE_JSONB>(JsonbField(writer.getOutput()->getBuffer(),
-
writer.getOutput()->getSize())));
- } else {
- traverseArray(element.getArray(), ctx);
- }
- // we should set has_nested_in_flatten to false when traverse array
finished for next array otherwise it will be true for next array
- ctx.has_nested_in_flatten = false;
- } else {
- appendValueIfNotDuplicate(ctx, ctx.builder.get_parts(),
getValueAsField(element));
- }
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::appendValueIfNotDuplicate(ParseContext& ctx,
- const
PathInData::Parts& path,
- Field&& value) {
- if (ctx.check_duplicate_json_path) {
- PathInData path_in_data(path);
- if (!ctx.visited_path_names.emplace(path_in_data.get_path()).second) {
- return;
- }
- }
- ctx.paths.push_back(path);
- ctx.values.push_back(std::move(value));
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::traverseObject(const JSONObject& object,
ParseContext& ctx) {
- ctx.paths.reserve(ctx.paths.size() + object.size());
- ctx.values.reserve(ctx.values.size() + object.size());
- auto check_key_length = [](const auto& key) {
- const size_t max_key_length =
cast_set<size_t>(config::variant_max_json_key_length);
- if (key.size() > max_key_length) {
- throw doris::Exception(
- doris::ErrorCode::INVALID_ARGUMENT,
- fmt::format("Key length exceeds maximum allowed size of {}
bytes.",
- max_key_length));
- }
- };
- auto traverse_object_member = [&](const auto& key, const auto& value) {
- check_key_length(key);
- ctx.builder.append(key, false);
- traverse(value, ctx);
- ctx.builder.pop_back();
- };
-
- for (auto it = object.begin(); it != object.end(); ++it) {
- const auto& [key, value] = *it;
- traverse_object_member(key, value);
- }
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::check_has_nested_object(const Element&
element) {
- if (element.isArray()) {
- const JSONArray& array = element.getArray();
- for (auto it = array.begin(); it != array.end(); ++it) {
- check_has_nested_object(*it);
- }
- }
- if (element.isObject()) {
- has_nested = true;
- }
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::traverseAsJsonb(const Element& element,
JsonbWriter& writer) {
- if (element.isObject()) {
- traverseObjectAsJsonb(element.getObject(), writer);
- } else if (element.isArray()) {
- traverseArrayAsJsonb(element.getArray(), writer);
- } else {
- writeValueAsJsonb(element, writer);
- }
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::traverseObjectAsJsonb(const JSONObject&
object,
- JsonbWriter& writer) {
- writer.writeStartObject();
- for (auto it = object.begin(); it != object.end(); ++it) {
- const auto& [key, value] = *it;
- const size_t max_key_length =
cast_set<size_t>(config::variant_max_json_key_length);
- if (key.size() > max_key_length) {
- throw doris::Exception(
- doris::ErrorCode::INVALID_ARGUMENT,
- fmt::format("Key length exceeds maximum allowed size of {}
bytes.",
- max_key_length));
- }
- writer.writeKey(key.data(), cast_set<uint8_t>(key.size()));
- traverseAsJsonb(value, writer);
- }
- writer.writeEndObject();
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::traverseArrayAsJsonb(const JSONArray& array,
JsonbWriter& writer) {
- writer.writeStartArray();
- for (auto it = array.begin(); it != array.end(); ++it) {
- traverseAsJsonb(*it, writer);
- }
- writer.writeEndArray();
-}
-
-// check isPrefix in PathInData::Parts. like : [{"a": {"c": {"b": 1}}}, {"a":
{"c": 2.2}}], "a.c" is prefix of "a.c.b"
-// return true if prefix is a prefix of parts
-static bool is_prefix(const PathInData::Parts& prefix, const
PathInData::Parts& parts) {
- if (prefix.size() >= parts.size()) {
- return false;
- }
- for (size_t i = 0; i < prefix.size(); ++i) {
- if (prefix[i].key != parts[i].key) {
- return false;
- }
- }
- return true;
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::traverseArray(const JSONArray& array,
ParseContext& ctx) {
- /// Traverse elements of array and collect an array of fields by each path.
- ParseArrayContext array_ctx;
- array_ctx.has_nested_in_flatten = ctx.has_nested_in_flatten;
- array_ctx.is_top_array = ctx.is_top_array;
- array_ctx.check_duplicate_json_path = ctx.check_duplicate_json_path;
- array_ctx.total_size = array.size();
- for (auto it = array.begin(); it != array.end(); ++it) {
- traverseArrayElement(*it, array_ctx);
- ++array_ctx.current_size;
- }
- auto&& arrays_by_path = array_ctx.arrays_by_path;
- if (arrays_by_path.empty()) {
- appendValueIfNotDuplicate(ctx, ctx.builder.get_parts(),
- Field::create_field<TYPE_ARRAY>(Array()));
- } else {
- ctx.paths.reserve(ctx.paths.size() + arrays_by_path.size());
- ctx.values.reserve(ctx.values.size() + arrays_by_path.size());
- for (auto it = arrays_by_path.begin(); it != arrays_by_path.end();
++it) {
- auto&& [path, path_array] = it->second;
- /// Merge prefix path and path of array element.
- ctx.builder.append(path, true);
- appendValueIfNotDuplicate(ctx, ctx.builder.get_parts(),
-
Field::create_field<TYPE_ARRAY>(std::move(path_array)));
- ctx.builder.pop_back(path.size());
- }
- }
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::traverseArrayElement(const Element& element,
- ParseArrayContext& ctx) {
- ParseContext element_ctx;
- element_ctx.has_nested_in_flatten = ctx.has_nested_in_flatten;
- element_ctx.is_top_array = ctx.is_top_array;
- element_ctx.check_duplicate_json_path = ctx.check_duplicate_json_path;
- traverse(element, element_ctx);
- auto& paths = element_ctx.paths;
- auto& values = element_ctx.values;
-
- if (element_ctx.has_nested_in_flatten && element_ctx.is_top_array) {
- checkAmbiguousStructure(ctx, paths);
- }
-
- size_t size = paths.size();
- size_t keys_to_update = ctx.arrays_by_path.size();
-
- for (size_t i = 0; i < size; ++i) {
- if (values[i].is_null()) {
- continue;
- }
-
- UInt128 hash = PathInData::get_parts_hash(paths[i]);
- auto found = ctx.arrays_by_path.find(hash);
-
- if (found != ctx.arrays_by_path.end()) {
- handleExistingPath(found->second, paths[i], values[i], ctx,
keys_to_update);
- } else {
- handleNewPath(hash, paths[i], values[i], ctx);
- }
- }
-
- // always fill missed values to keep element-level association between
keys.
- if (keys_to_update) {
- fillMissedValuesInArrays(ctx);
- }
-}
-
-// check if the structure of top_array is ambiguous like:
-// [{"a": {"b": {"c": 1}}}, {"a": {"b": 1}}] a.b is ambiguous
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::checkAmbiguousStructure(
- const ParseArrayContext& ctx, const std::vector<PathInData::Parts>&
paths) {
- for (auto&& current_path : paths) {
- for (auto it = ctx.arrays_by_path.begin(); it !=
ctx.arrays_by_path.end(); ++it) {
- auto&& [p, _] = it->second;
- if (is_prefix(p, current_path) || is_prefix(current_path, p)) {
- throw doris::Exception(doris::ErrorCode::INVALID_ARGUMENT,
- "Ambiguous structure of top_array
nested subcolumns: {}, {}",
- PathInData(p).to_jsonpath(),
- PathInData(current_path).to_jsonpath());
- }
- }
- }
-}
-
-template <typename ParserImpl>
-void
JSONDataParser<ParserImpl>::handleExistingPath(std::pair<PathInData::Parts,
Array>& path_data,
- const PathInData::Parts&
path, Field& value,
- ParseArrayContext& ctx,
- size_t& keys_to_update) {
- auto& path_array = path_data.second;
- // keep arrays aligned for all keys (including top-level arrays).
- assert(path_array.size() == ctx.current_size);
- // If current element of array is part of Nested,
- // collect its size or check it if the size of
- // the Nested has been already collected.
- auto nested_key = getNameOfNested(path, value);
- if (!nested_key.empty()) {
- size_t array_size = value.get<TYPE_ARRAY>().size();
- auto& current_nested_sizes = ctx.nested_sizes_by_key[nested_key];
- if (current_nested_sizes.size() == ctx.current_size) {
- current_nested_sizes.push_back(array_size);
- } else if (array_size != current_nested_sizes.back()) {
- throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
- "Array sizes mismatched ({} and {})",
array_size,
- current_nested_sizes.back());
- }
- }
-
- path_array.push_back(std::move(value));
- --keys_to_update;
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::handleNewPath(UInt128 hash, const
PathInData::Parts& path,
- Field& value,
ParseArrayContext& ctx) {
- Array path_array;
- path_array.reserve(ctx.total_size);
-
- // always resize to keep alignment.
- path_array.resize(ctx.current_size);
-
- auto nested_key = getNameOfNested(path, value);
- if (!nested_key.empty()) {
- size_t array_size = value.get<TYPE_ARRAY>().size();
- auto& current_nested_sizes = ctx.nested_sizes_by_key[nested_key];
- if (current_nested_sizes.empty()) {
- current_nested_sizes.resize(ctx.current_size);
- } else {
- // If newly added element is part of the Nested then
- // resize its elements to keep correct sizes of Nested arrays.
- for (size_t j = 0; j < ctx.current_size; ++j) {
- path_array[j] =
Field::create_field<TYPE_ARRAY>(Array(current_nested_sizes[j]));
- }
- }
- if (current_nested_sizes.size() == ctx.current_size) {
- current_nested_sizes.push_back(array_size);
- } else if (array_size != current_nested_sizes.back()) {
- throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR,
- "Array sizes mismatched ({} and {})",
array_size,
- current_nested_sizes.back());
- }
- }
-
- path_array.push_back(std::move(value));
- auto& elem = ctx.arrays_by_path[hash];
- elem.first = std::move(path);
- elem.second = std::move(path_array);
-}
-
-template <typename ParserImpl>
-void JSONDataParser<ParserImpl>::fillMissedValuesInArrays(ParseArrayContext&
ctx) {
- for (auto it = ctx.arrays_by_path.begin(); it != ctx.arrays_by_path.end();
++it) {
- auto& [path, path_array] = it->second;
- assert(path_array.size() == ctx.current_size || path_array.size() ==
ctx.current_size + 1);
- if (path_array.size() == ctx.current_size) {
- bool inserted = tryInsertDefaultFromNested(ctx, path, path_array);
- if (!inserted) {
- path_array.emplace_back();
- }
- }
- }
-}
-
-template <typename ParserImpl>
-bool JSONDataParser<ParserImpl>::tryInsertDefaultFromNested(ParseArrayContext&
ctx,
- const
PathInData::Parts& path,
- Array& array) {
- /// If there is a collected size of current Nested
- /// then insert array of this size as a default value.
- if (path.empty() || array.empty()) {
- return false;
- }
- /// Last element is not Null, because otherwise this path wouldn't exist.
- auto nested_key = getNameOfNested(path, array.back());
- if (nested_key.empty()) {
- return false;
- }
- auto mapped = ctx.nested_sizes_by_key.find(nested_key);
- if (mapped == ctx.nested_sizes_by_key.end()) {
- return false;
- }
- auto& current_nested_sizes = mapped->second;
- assert(current_nested_sizes.size() == ctx.current_size ||
- current_nested_sizes.size() == ctx.current_size + 1);
- /// If all keys of Nested were missed then add a zero length.
- if (current_nested_sizes.size() == ctx.current_size) {
- current_nested_sizes.push_back(0);
- }
- size_t array_size = current_nested_sizes.back();
- array.push_back(Field::create_field<TYPE_ARRAY>(Array(array_size)));
- return true;
-}
-
-template <typename ParserImpl>
-StringRef JSONDataParser<ParserImpl>::getNameOfNested(const PathInData::Parts&
path,
- const Field& value) {
- if (value.get_type() != PrimitiveType::TYPE_ARRAY || path.empty()) {
- return {};
- }
- /// Find first key that is marked as nested,
- /// because we may have struct of Nested and there could be
- /// several arrays with the same prefix, but with independent sizes.
- /// Consider we have array element with type `k2 Struct(k3 Nested(...), k5
Nested(...))`
- /// Then subcolumns `k2.k3` and `k2.k5` may have indepented sizes and we
should extract
- /// `k3` and `k5` keys instead of `k2`.
- for (const auto& part : path) {
- if (part.is_nested) {
- return {part.key.data(), part.key.size()};
- }
- }
- return {};
-}
-
-template class JSONDataParser<SimdJSONParser>;
-} // namespace doris
diff --git a/be/src/util/json/json_parser.h b/be/src/util/json/json_parser.h
deleted file mode 100644
index ee91765d44d..00000000000
--- a/be/src/util/json/json_parser.h
+++ /dev/null
@@ -1,179 +0,0 @@
-// 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.
-// This file is copied from
-//
https://github.com/ClickHouse/ClickHouse/blob/master/src/Common/JSONParsers/SimdJSONParser.h
-// and modified by Doris
-
-#pragma once
-
-#include <parallel_hashmap/phmap.h>
-#include <stddef.h>
-
-#include <optional>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "core/column/column.h"
-#include "core/data_type/primitive_type.h"
-#include "core/field.h"
-#include "core/string_ref.h"
-#include "core/uint128.h"
-#include "util/json/path_in_data.h"
-#include "util/json/simd_json_parser.h"
-#include "util/jsonb_writer.h"
-
-namespace doris {
-
-template <typename Element>
-Field getValueAsField(const Element& element) {
- // bool will convert to type FiledType::UInt64
- if (element.isBool()) {
- return Field::create_field<TYPE_BOOLEAN>(element.getBool());
- }
- if (element.isInt64()) {
- return Field::create_field<TYPE_BIGINT>(element.getInt64());
- }
- // doris only support signed integers at present
- // use largeint to store unsigned int64
- if (element.isUInt64()) {
- return
Field::create_field<TYPE_LARGEINT>(static_cast<int128_t>(element.getUInt64()));
- }
- if (element.isDouble()) {
- return Field::create_field<TYPE_DOUBLE>(element.getDouble());
- }
- if (element.isString()) {
- return Field::create_field<TYPE_STRING>(String(element.getString()));
- }
- if (element.isNull()) {
- return Field();
- }
- return Field();
-}
-
-template <typename Element>
-void writeValueAsJsonb(const Element& element, JsonbWriter& writer) {
- // bool will convert to type FiledType::UInt64
- if (element.isBool()) {
- writer.writeBool(element.getBool());
- return;
- }
- if (element.isInt64()) {
- writer.writeInt64(element.getInt64());
- return;
- }
- // doris only support signed integers at present
- // use largeint to store unsigned int64
- if (element.isUInt64()) {
- writer.writeInt128(static_cast<int128_t>(element.getUInt64()));
- return;
- }
- if (element.isDouble()) {
- writer.writeDouble(element.getDouble());
- return;
- }
- if (element.isString()) {
- writer.writeStartString();
- std::string_view str = element.getString();
- writer.writeString(str.data(), str.size());
- writer.writeEndString();
- return;
- }
- if (element.isNull()) {
- writer.writeNull();
- return;
- }
-}
-
-struct ParseConfig {
- bool deprecated_enable_flatten_nested = false;
- bool check_duplicate_json_path = false;
- enum class ParseTo {
- OnlySubcolumns = 0,
- OnlyDocValueColumn = 1,
- };
- ParseTo parse_to = ParseTo::OnlySubcolumns;
-};
-/// Result of parsing of a document.
-/// Contains all paths extracted from document
-/// and values which are related to them.
-struct ParseResult {
- std::vector<PathInData> paths;
- std::vector<Field> values;
-};
-template <typename ParserImpl>
-class JSONDataParser {
-public:
- using Element = typename ParserImpl::Element;
- using JSONObject = typename ParserImpl::Object;
- using JSONArray = typename ParserImpl::Array;
- std::optional<ParseResult> parse(const char* begin, size_t length, const
ParseConfig& config);
-
-private:
- struct ParseContext {
- PathInDataBuilder builder;
- std::vector<PathInData::Parts> paths;
- std::vector<Field> values;
- phmap::flat_hash_set<std::string> visited_path_names;
- bool deprecated_enable_flatten_nested = false;
- bool check_duplicate_json_path = false;
- bool has_nested_in_flatten = false;
- bool is_top_array = false;
- };
- using PathPartsWithArray = std::pair<PathInData::Parts, Array>;
- using PathToArray = phmap::flat_hash_map<UInt128, PathPartsWithArray,
UInt128TrivialHash>;
- using KeyToSizes = phmap::flat_hash_map<StringRef, std::vector<size_t>,
StringRefHash>;
- struct ParseArrayContext {
- size_t current_size = 0;
- size_t total_size = 0;
- PathToArray arrays_by_path;
- KeyToSizes nested_sizes_by_key;
- bool has_nested_in_flatten = false;
- bool is_top_array = false;
- bool check_duplicate_json_path = false;
- };
- void traverse(const Element& element, ParseContext& ctx);
- void traverseObject(const JSONObject& object, ParseContext& ctx);
- void traverseArray(const JSONArray& array, ParseContext& ctx);
- void appendValueIfNotDuplicate(ParseContext& ctx, const PathInData::Parts&
path, Field&& value);
- void traverseArrayElement(const Element& element, ParseArrayContext& ctx);
- void checkAmbiguousStructure(const ParseArrayContext& ctx,
- const std::vector<PathInData::Parts>& paths);
- void handleExistingPath(std::pair<PathInData::Parts, Array>& path_data,
- const PathInData::Parts& path, Field& value,
ParseArrayContext& ctx,
- size_t& keys_to_update);
- void handleNewPath(UInt128 hash, const PathInData::Parts& path, Field&
value,
- ParseArrayContext& ctx);
- static void fillMissedValuesInArrays(ParseArrayContext& ctx);
- static bool tryInsertDefaultFromNested(ParseArrayContext& ctx, const
PathInData::Parts& path,
- Array& array);
- static StringRef getNameOfNested(const PathInData::Parts& path, const
Field& value);
-
- bool has_nested = false;
- void check_has_nested_object(const Element& element);
- void traverseAsJsonb(const Element& element, JsonbWriter& writer);
- void traverseObjectAsJsonb(const JSONObject& object, JsonbWriter& writer);
- void traverseArrayAsJsonb(const JSONArray& array, JsonbWriter& writer);
-
- ParserImpl parser;
-};
-
-class SimdJSONParser;
-/// Instantiated once in json_parser.cpp; suppresses per-TU implicit
instantiation.
-extern template class JSONDataParser<SimdJSONParser>;
-
-} // namespace doris
diff --git a/be/test/core/jsonb/json_parser_test.cpp
b/be/test/core/jsonb/json_parser_test.cpp
deleted file mode 100644
index f8cfdf8e162..00000000000
--- a/be/test/core/jsonb/json_parser_test.cpp
+++ /dev/null
@@ -1,481 +0,0 @@
-// 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 "util/json/json_parser.h"
-
-#include <gtest/gtest.h>
-
-#include <vector>
-
-#include "common/config.h"
-#include "core/string_ref.h"
-
-using doris::JSONDataParser;
-using doris::SimdJSONParser;
-using doris::ParseConfig;
-
-TEST(JsonParserTest, ParseSimpleTypes) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
-
- // int
- auto result = parser.parse("123", 3, config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
-
- auto parse_result_int = result.value();
- EXPECT_EQ(parse_result_int.paths[0].get_path(), "");
- EXPECT_EQ(parse_result_int.values[0].get_type(),
doris::PrimitiveType::TYPE_BIGINT);
-
- // double
- result = parser.parse("1.23", 4, config);
- ASSERT_TRUE(result.has_value());
-
- auto parse_result_double = result.value();
- EXPECT_EQ(parse_result_double.paths[0].get_path(), "");
- EXPECT_EQ(parse_result_double.values[0].get_type(),
doris::PrimitiveType::TYPE_DOUBLE);
-
- // bool
- result = parser.parse("true", 4, config);
- ASSERT_TRUE(result.has_value());
-
- auto parse_result_bool = result.value();
- EXPECT_EQ(parse_result_bool.values[0].get_type(),
doris::PrimitiveType::TYPE_BOOLEAN);
-
- // null
- result = parser.parse("null", 4, config);
- ASSERT_TRUE(result.has_value());
- auto parse_result_null = result.value();
- EXPECT_EQ(parse_result_null.paths[0].get_path(), "");
- EXPECT_EQ(parse_result_null.values[0].get_type(),
doris::PrimitiveType::TYPE_NULL);
-
- // string
- result = parser.parse("\"abc\"", 5, config);
- ASSERT_TRUE(result.has_value());
- auto parse_result_string = result.value();
- EXPECT_EQ(parse_result_string.paths[0].get_path(), "");
- EXPECT_EQ(parse_result_string.values[0].get_type(),
doris::PrimitiveType::TYPE_STRING);
-
- // largeint
- result = parser.parse("12345678901234567890", 20, config);
- ASSERT_TRUE(result.has_value());
- auto parse_result_bigint = result.value();
- EXPECT_EQ(parse_result_bigint.paths[0].get_path(), "");
- EXPECT_EQ(parse_result_bigint.values[0].get_type(),
doris::PrimitiveType::TYPE_LARGEINT);
-}
-
-TEST(JsonParserTest, ParseObjectAndArray) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
-
- // Object
- auto result = parser.parse(R"({"a":1,"b":2})", 13, config);
- ASSERT_TRUE(result.has_value());
- auto& parse_result_object = result.value();
- EXPECT_EQ(parse_result_object.values.size(), 2);
- EXPECT_EQ(parse_result_object.paths.size(), 2);
- EXPECT_EQ(parse_result_object.values[0].get_type(),
doris::PrimitiveType::TYPE_BIGINT);
- EXPECT_EQ(parse_result_object.values[1].get_type(),
doris::PrimitiveType::TYPE_BIGINT);
- EXPECT_EQ(parse_result_object.paths[0].get_path(), "a");
- EXPECT_EQ(parse_result_object.paths[1].get_path(), "b");
-
- // Array
- result = parser.parse("[1,2,3]", 7, config);
- ASSERT_TRUE(result.has_value());
- auto& parse_result_array = result.value();
- EXPECT_EQ(parse_result_array.paths[0].get_path(), "");
- EXPECT_EQ(parse_result_array.values[0].get_type(),
doris::PrimitiveType::TYPE_ARRAY);
-
- std::string json = R"([1, "string", null, true, 1.23,
12345678901234567890])";
- result = parser.parse(json.c_str(), json.size(), config);
- ASSERT_TRUE(result.has_value());
- auto& parse_result_array_2 = result.value();
- EXPECT_EQ(parse_result_array_2.paths[0].get_path(), "");
- EXPECT_EQ(parse_result_array_2.values[0].get_type(),
doris::PrimitiveType::TYPE_ARRAY);
- auto& array_field =
parse_result_array_2.values[0].get<doris::PrimitiveType::TYPE_ARRAY>();
-
- EXPECT_EQ(array_field.size(), 6);
- EXPECT_EQ(array_field[0].get_type(), doris::PrimitiveType::TYPE_BIGINT);
- EXPECT_EQ(array_field[1].get_type(), doris::PrimitiveType::TYPE_STRING);
- EXPECT_EQ(array_field[2].get_type(), doris::PrimitiveType::TYPE_NULL);
- EXPECT_EQ(array_field[3].get_type(), doris::PrimitiveType::TYPE_BOOLEAN);
- EXPECT_EQ(array_field[4].get_type(), doris::PrimitiveType::TYPE_DOUBLE);
- EXPECT_EQ(array_field[5].get_type(), doris::PrimitiveType::TYPE_LARGEINT);
-}
-
-TEST(JsonParserTest, ParseMultiLevelNestedArray) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
-
- auto result = parser.parse("[[1,2],[3,4]]", 13, config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
- EXPECT_EQ(result->values[0].get_type(), doris::PrimitiveType::TYPE_ARRAY);
-
- result = parser.parse("[[[1],[2]],[[3],[4]]]", 21, config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
- EXPECT_EQ(result->values[0].get_type(), doris::PrimitiveType::TYPE_ARRAY);
-
- result = parser.parse("[[1,2],[3],[4,5,6]]", 19, config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
-
- // Test complex nested structure
- config.deprecated_enable_flatten_nested = false;
- std::string json1 = R"({"a":[[1,2],[3],[4,5,6]]})";
- // multi level nested array in object
- result = parser.parse(json1.c_str(), json1.size(), config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
- EXPECT_EQ(result->values[0].get_type(), doris::PrimitiveType::TYPE_ARRAY);
-
- std::string json = R"({"nested": [{"a": [1,2,3]}]})";
- // result should be jsonbField
- result = parser.parse(json.c_str(), json.size(), config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
- EXPECT_EQ(result->values[0].get_type(), doris::PrimitiveType::TYPE_JSONB);
-
- // multi level nested array in nested array object
- std::string json2 = R"({"a":[{"b":[[1,2,3]]}]})";
- result = parser.parse(json2.c_str(), json2.size(), config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
- EXPECT_EQ(result->values[0].get_type(), doris::PrimitiveType::TYPE_JSONB);
-
- // test flatten nested
- config.deprecated_enable_flatten_nested = true;
- // TODO: checkAmbiguousStructure is only called when has_nested_in_flatten
&& is_top_array.
- // These JSONs are objects (not top-level arrays), so is_top_array=false
and the check is skipped.
- // EXPECT_ANY_THROW(parser.parse(json.c_str(), json.size(), config));
- // test flatten nested with multi level nested array
- // no throw because it is not nested object array
- result = parser.parse(json1.c_str(), json1.size(), config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
- EXPECT_EQ(result->values[0].get_type(), doris::PrimitiveType::TYPE_ARRAY);
-
- // TODO: Same reason as above — object-level array, is_top_array=false,
check skipped.
- // EXPECT_ANY_THROW(parser.parse(json2.c_str(), json2.size(), config));
-}
-
-TEST(JsonParserTest, ParseNestedAndFlatten) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
- config.deprecated_enable_flatten_nested = true;
-
- std::string json = R"({"a":[{"b":1},{"b":2}]})";
- auto result = parser.parse(json.c_str(), json.size(), config);
- ASSERT_TRUE(result.has_value());
- EXPECT_GT(result->values.size(), 0);
-
- config.deprecated_enable_flatten_nested = false;
- std::string json2 = R"({"a":[{"b":1},{"b":2}]})";
- result = parser.parse(json2.c_str(), json2.size(), config);
- ASSERT_TRUE(result.has_value());
-}
-
-TEST(JsonParserTest, ParseInvalidJson) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
-
- auto result = parser.parse("{a:1}", 5, config);
- ASSERT_FALSE(result.has_value());
-
- result = parser.parse("", 0, config);
- ASSERT_FALSE(result.has_value());
-}
-
-TEST(JsonParserTest, ParseCornerCases) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
-
- auto result = parser.parse("{}", 2, config);
- ASSERT_TRUE(result.has_value());
-
- result = parser.parse("[]", 2, config);
- ASSERT_TRUE(result.has_value());
-
- result = parser.parse(R"({"a":"\n\t"})", 12, config);
- ASSERT_TRUE(result.has_value());
-}
-
-// Test cases for the selected code functionality
-TEST(JsonParserTest, TestIsPrefixFunction) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
-
- // Test is_prefix functionality through nested path parsing
- // This tests the is_prefix function used in checkAmbiguousStructure
-
- // Test case 1: Simple nested paths that should not be ambiguous
- std::string json1 = R"({"a": [{"b": 1}, {"b": 2}]})";
- auto result1 = parser.parse(json1.c_str(), json1.size(), config);
- ASSERT_TRUE(result1.has_value());
-
- // Test case 2: More complex nested paths
- std::string json2 = R"({"a": [{"b": {"c": 1}}, {"b": {"c": 2}}]})";
- auto result2 = parser.parse(json2.c_str(), json2.size(), config);
- ASSERT_TRUE(result2.has_value());
-
- // Test case 3: Deep nested structure
- std::string json3 = R"({"level1": {"level2": [{"level3": {"level4":
1}}]}})";
- auto result3 = parser.parse(json3.c_str(), json3.size(), config);
- ASSERT_TRUE(result3.has_value());
-}
-
-TEST(JsonParserTest, TestAmbiguousStructureDetection) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
- config.deprecated_enable_flatten_nested = true;
-
- // TODO: The following 3 cases no longer throw because
checkAmbiguousStructure requires
- // has_nested_in_flatten && is_top_array. "b" contains plain arrays (not
nested objects),
- // so has_nested=false → has_nested_in_flatten=false, and the ambiguity
check is skipped.
-
- // Test case 1: Arrays with different sizes in nested structure
- std::string json1 = R"([{"b": [1, 2]}, {"b": [1, 2, 3]}])";
- // EXPECT_ANY_THROW(parser.parse(json1.c_str(), json1.size(), config));
-
- // Test case 2: Arrays with same sizes should not throw
- std::string json2 = R"([{"b": [1, 2]}, {"b": [3, 4]}])";
- // EXPECT_ANY_THROW(parser.parse(json2.c_str(), json2.size(), config));
-
- // Test case 3: More complex nested array size mismatch (object-level,
is_top_array=false)
- std::string json3 = R"({"nested": [{"arr": [[1, 2], [3]]}, {"arr": [[1,
2], [3, 4]]}]})";
- // EXPECT_ANY_THROW(parser.parse(json3.c_str(), json3.size(), config));
-
- // Test case 4: Ambiguous structure with prefix paths
- // This should trigger the ambiguous structure exception
- std::string json4 = R"([{"a": {"c": 1}}, {"a": 2}])";
- EXPECT_ANY_THROW(parser.parse(json4.c_str(), json4.size(), config));
-}
-
-TEST(JsonParserTest, TestNestedArrayHandling) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
- config.deprecated_enable_flatten_nested = true;
-
- // Test case 1: Simple nested array handling
- std::string json1 = R"([{"b": 1}, {"c": 2}])";
- auto result1 = parser.parse(json1.c_str(), json1.size(), config);
- ASSERT_TRUE(result1.has_value());
- EXPECT_GT(result1->values.size(), 0);
-
- // Test case 2: Multi-level nested array
- std::string json2 = R"([{"a": {"b": 1}}, {"a": {"b": 2}}])";
- auto result2 = parser.parse(json2.c_str(), json2.size(), config);
- ASSERT_TRUE(result2.has_value());
- EXPECT_GT(result2->values.size(), 0);
-}
-
-TEST(JsonParserTest, TestNestedArrayWithDifferentConfigs) {
- JSONDataParser<SimdJSONParser> parser;
-
- // Test with flatten_nested = false
- ParseConfig config1;
- config1.deprecated_enable_flatten_nested = false;
-
- std::string json1 = R"([{"b": [1, 2]}, {"b": [3, 4]}])";
- auto result1 = parser.parse(json1.c_str(), json1.size(), config1);
- ASSERT_TRUE(result1.has_value());
- EXPECT_EQ(result1->values.size(), 1);
- EXPECT_EQ(result1->values[0].get_type(), doris::PrimitiveType::TYPE_JSONB);
-
- // Test with flatten_nested = true
- ParseConfig config2;
- config2.deprecated_enable_flatten_nested = true;
-
- // TODO: "b" contains plain arrays (no nested objects), so
has_nested=false,
- // has_nested_in_flatten=false, and checkAmbiguousStructure is not called.
- // EXPECT_ANY_THROW(parser.parse(json1.c_str(), json1.size(), config2));
-}
-
-// Test case for directly calling handleNewPath to cover the if
(!nested_key.empty()) branch
-TEST(JsonParserTest, TestHandleNewPathDirectCall) {
- JSONDataParser<SimdJSONParser> parser;
-
- // Create a ParseArrayContext
- JSONDataParser<SimdJSONParser>::ParseArrayContext ctx;
- ctx.current_size = 1;
- ctx.total_size = 2;
- ctx.has_nested_in_flatten = true;
- ctx.is_top_array = true;
-
- // Create a path with nested parts
- doris::PathInData::Parts path;
- // Create a nested part (is_nested = true)
- path.emplace_back("nested_key", true, 0); // is_nested = true
- path.emplace_back("inner_key", false, 0); // is_nested = false
-
- // Create a Field with array type (required for getNameOfNested to return
non-empty)
- doris::Array array_data;
- array_data.push_back(doris::Field::create_field<doris::TYPE_INT>(1));
- array_data.push_back(doris::Field::create_field<doris::TYPE_INT>(2));
- doris::Field value =
doris::Field::create_field<doris::TYPE_ARRAY>(std::move(array_data));
-
- // Create hash for the path
- UInt128 hash = doris::PathInData::get_parts_hash(path);
-
- // Call handleNewPath directly
- // This should trigger the if (!nested_key.empty()) branch
- parser.handleNewPath(hash, path, value, ctx);
-
- // Verify that the nested_sizes_by_key was populated
- EXPECT_EQ(ctx.nested_sizes_by_key.size(), 1);
-
- // Verify that the arrays_by_path was populated
- EXPECT_EQ(ctx.arrays_by_path.size(), 1);
- EXPECT_TRUE(ctx.arrays_by_path.find(hash) != ctx.arrays_by_path.end());
-}
-
-// Test case for testing the else branch in handleNewPath (when nested_sizes
is not empty)
-TEST(JsonParserTest, TestHandleNewPathElseBranch) {
- JSONDataParser<SimdJSONParser> parser;
-
- // Create a ParseArrayContext
- JSONDataParser<SimdJSONParser>::ParseArrayContext ctx;
- ctx.current_size = 2; // Start with size 2
- ctx.total_size = 3;
- ctx.has_nested_in_flatten = true;
- ctx.is_top_array = true;
-
- // Create a path with nested parts
- doris::PathInData::Parts path;
- path.emplace_back("nested_key", true, 0);
- path.emplace_back("inner_key", false, 0);
-
- // Create a Field with array type
- doris::Array array_data;
- array_data.push_back(doris::Field::create_field<doris::TYPE_INT>(1));
- array_data.push_back(doris::Field::create_field<doris::TYPE_INT>(2));
- doris::Field value =
doris::Field::create_field<doris::TYPE_ARRAY>(std::move(array_data));
-
- // Create hash for the path
- UInt128 hash = doris::PathInData::get_parts_hash(path);
-
- // First call to populate nested_sizes_by_key
- parser.handleNewPath(hash, path, value, ctx);
-
- // Verify nested_sizes_by_key was populated
-
EXPECT_EQ(ctx.nested_sizes_by_key.at(doris::StringRef("nested_key")).size(), 3);
- EXPECT_EQ(ctx.nested_sizes_by_key.at(doris::StringRef("nested_key"))[0],
0);
-
- // Create another array with same size
- doris::Array array_data2;
- array_data2.push_back(doris::Field::create_field<doris::TYPE_INT>(3));
- array_data2.push_back(doris::Field::create_field<doris::TYPE_INT>(4));
- doris::Field value2 =
doris::Field::create_field<doris::TYPE_ARRAY>(std::move(array_data2));
-
- // Second call should trigger the else branch (nested_sizes is not empty)
- ctx.is_top_array = false;
- ctx.has_nested_in_flatten = false;
- parser.handleNewPath(hash, path, value2, ctx);
-
- // Verify nested_sizes_by_key was updated
-
EXPECT_EQ(ctx.nested_sizes_by_key.at(doris::StringRef("nested_key")).size(), 3);
- EXPECT_EQ(ctx.nested_sizes_by_key.at(doris::StringRef("nested_key"))[1],
0);
-}
-
-TEST(JsonParserTest, ParseUInt64) {
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
-
- std::string json = R"({"a": 18446744073709551615})";
- auto result = parser.parse(json.c_str(), json.size(), config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
- EXPECT_EQ(result->paths[0].get_path(), "a");
- EXPECT_EQ(result->values[0].get_type(),
doris::PrimitiveType::TYPE_LARGEINT);
- EXPECT_EQ(result->values[0].get<doris::PrimitiveType::TYPE_LARGEINT>(),
- 18446744073709551615ULL);
-
- std::string array_json = R"({"a": [18446744073709551615]})";
- result = parser.parse(array_json.c_str(), array_json.size(), config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
- EXPECT_EQ(result->paths[0].get_path(), "a");
- EXPECT_EQ(result->values[0].get_type(), doris::PrimitiveType::TYPE_ARRAY);
- auto& array_field =
result->values[0].get<doris::PrimitiveType::TYPE_ARRAY>();
- EXPECT_EQ(array_field.size(), 1);
- EXPECT_EQ(array_field[0].get_type(), doris::PrimitiveType::TYPE_LARGEINT);
- EXPECT_EQ(array_field[0].get<doris::PrimitiveType::TYPE_LARGEINT>(),
18446744073709551615ULL);
-
- std::string nested_json = R"({"a": [{"b": 18446744073709551615}]})";
- config.deprecated_enable_flatten_nested = true;
- result = parser.parse(nested_json.c_str(), nested_json.size(), config);
- ASSERT_TRUE(result.has_value());
- EXPECT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->paths.size(), 1);
- EXPECT_EQ(result->values[0].get_type(), doris::PrimitiveType::TYPE_ARRAY);
- auto& array_field_2 =
result->values[0].get<doris::PrimitiveType::TYPE_ARRAY>();
- EXPECT_EQ(array_field_2.size(), 1);
- EXPECT_EQ(array_field_2[0].get_type(),
doris::PrimitiveType::TYPE_LARGEINT);
- EXPECT_EQ(array_field_2[0].get<doris::PrimitiveType::TYPE_LARGEINT>(),
18446744073709551615ULL);
-}
-
-TEST(JsonParserTest, KeyLengthLimitByConfig) {
- struct ScopedMaxJsonKeyLength {
- int32_t old_value;
- explicit ScopedMaxJsonKeyLength(int32_t new_value)
- : old_value(doris::config::variant_max_json_key_length) {
- doris::config::variant_max_json_key_length = new_value;
- }
- ~ScopedMaxJsonKeyLength() { doris::config::variant_max_json_key_length
= old_value; }
- };
-
- JSONDataParser<SimdJSONParser> parser;
- ParseConfig config;
-
- {
- ScopedMaxJsonKeyLength guard(10);
- std::string key11(11, 'a');
-
- std::string obj_json = "{\"" + key11 + "\": 1}";
- EXPECT_ANY_THROW(parser.parse(obj_json.c_str(), obj_json.size(),
config));
-
- config.deprecated_enable_flatten_nested = false;
- std::string jsonb_json = "{\"a\": [{\"" + key11 + "\": 1}]}";
- EXPECT_ANY_THROW(parser.parse(jsonb_json.c_str(), jsonb_json.size(),
config));
- }
-
- {
- ScopedMaxJsonKeyLength guard(255);
- std::string key255(255, 'b');
-
- std::string obj_json = "{\"" + key255 + "\": 1}";
- auto result = parser.parse(obj_json.c_str(), obj_json.size(), config);
- ASSERT_TRUE(result.has_value());
-
- config.deprecated_enable_flatten_nested = false;
- std::string jsonb_json = "{\"a\": [{\"" + key255 + "\": 1}]}";
- result = parser.parse(jsonb_json.c_str(), jsonb_json.size(), config);
- ASSERT_TRUE(result.has_value());
- ASSERT_EQ(result->values.size(), 1);
- EXPECT_EQ(result->values[0].get_type(),
doris::PrimitiveType::TYPE_JSONB);
- }
-}
diff --git a/be/test/exprs/function/cast/cast_to_decimal128_perf.cpp
b/be/test/exprs/function/cast/cast_to_decimal128_perf.cpp
index b371de445d6..1ec43f8317a 100644
--- a/be/test/exprs/function/cast/cast_to_decimal128_perf.cpp
+++ b/be/test/exprs/function/cast/cast_to_decimal128_perf.cpp
@@ -26,7 +26,6 @@
#include "core/data_type/primitive_type.h"
#include "core/field.h"
#include "exprs/function/cast/cast_to_decimal_test.h"
-#include "util/json/json_parser.h"
#include "util/string_parser.hpp"
namespace doris {
diff --git a/be/test/storage/variant/index_storage_variant_debug_point_test.cpp
b/be/test/storage/variant/index_storage_variant_debug_point_test.cpp
index 9a5007b8eeb..475dee85190 100644
--- a/be/test/storage/variant/index_storage_variant_debug_point_test.cpp
+++ b/be/test/storage/variant/index_storage_variant_debug_point_test.cpp
@@ -210,7 +210,6 @@ TEST_F(IndexStorageVariantDebugPointTest,
ArrayPathIndexAcceptsMixedTypedElement
{R"({"c_arr": ["text"]})", R"({"c_arr": [1.1]})", R"({"c_arr":
[1.0]})",
R"({"c_arr": [90]})", R"({"c_arr": [90999999999999]})"},
0));
- rowset.batches.back().parse_to = ParseConfig::ParseTo::OnlyDocValueColumn;
auto rowset_result = write_rowset(rowset);
ASSERT_TRUE(rowset_result.has_value()) << rowset_result.error();
diff --git a/be/test/testutil/index_storage_test_util.h
b/be/test/testutil/index_storage_test_util.h
index 31995566e17..873ce5db4fc 100644
--- a/be/test/testutil/index_storage_test_util.h
+++ b/be/test/testutil/index_storage_test_util.h
@@ -40,7 +40,6 @@
#include "storage/rowset/rowset.h"
#include "storage/tablet/tablet.h"
#include "storage/tablet/tablet_schema.h"
-#include "util/json/json_parser.h"
namespace doris {
@@ -117,7 +116,6 @@ struct IndexBatch {
std::vector<ColumnPtr> variant_columns_by_column;
bool deprecated_enable_flatten_nested = false;
bool check_duplicate_json_path = false;
- ParseConfig::ParseTo parse_to = ParseConfig::ParseTo::OnlySubcolumns;
static IndexBatch single_text(std::vector<std::string> values, int32_t
first_key = 0);
static IndexBatch single_variant(std::vector<std::string> jsons, int32_t
first_key = 0);
diff --git a/be/test/util/variant/variant_field_test.cpp
b/be/test/util/variant/variant_field_test.cpp
index 2bbec8cfb38..1c072fd80db 100644
--- a/be/test/util/variant/variant_field_test.cpp
+++ b/be/test/util/variant/variant_field_test.cpp
@@ -30,8 +30,6 @@
#include "common/exception.h"
#include "core/value/variant/variant_parquet_encoding.h"
#include "exprs/function/parse/variant_string_parse.h"
-#include "util/json/json_parser.h"
-#include "util/json/simd_json_parser.h"
namespace doris {
namespace {
@@ -541,29 +539,11 @@ TEST(VariantFieldTest, AllComparisonsThrow) {
EXPECT_THROW(static_cast<void>(left > right), Exception);
}
-// This is a narrow current-source comparison, not the deferred T0.2 semantics
baseline.
-TEST(VariantFieldTest, LegacyJsonDataParserStableSubsetDoesNotReplaceT02) {
- JSONDataParser<SimdJSONParser> legacy;
- ParseConfig config;
-
- auto old_scalar = legacy.parse("123", 3, config);
- ASSERT_TRUE(old_scalar.has_value());
- ASSERT_EQ(old_scalar->values.size(), 1);
- EXPECT_EQ(old_scalar->values[0].get<TYPE_BIGINT>(), 123);
+TEST(VariantFieldTest, EncodeJsonStableSubset) {
EXPECT_EQ(encode_json("123").ref().get_int(), 123);
-
- old_scalar = legacy.parse("\"text\"", 6, config);
- ASSERT_TRUE(old_scalar.has_value());
- EXPECT_EQ(old_scalar->values[0].get<TYPE_STRING>(), "text");
EXPECT_EQ(encode_json("\"text\"").ref().get_string(), StringRef("text"));
- const std::string object_json = R"({"a":1,"b":"x"})";
- auto old_object = legacy.parse(object_json.data(), object_json.size(),
config);
- ASSERT_TRUE(old_object.has_value());
- ASSERT_EQ(old_object->paths.size(), 2);
- EXPECT_EQ(old_object->paths[0].get_path(), "a");
- EXPECT_EQ(old_object->paths[1].get_path(), "b");
- VariantField new_object = encode_json(object_json);
+ VariantField new_object = encode_json(R"({"a":1,"b":"x"})");
VariantRef a;
ASSERT_TRUE(new_object.ref().object_find(StringRef("a"), &a));
EXPECT_EQ(a.get_int(), 1);
@@ -571,29 +551,14 @@ TEST(VariantFieldTest,
LegacyJsonDataParserStableSubsetDoesNotReplaceT02) {
ASSERT_TRUE(new_object.ref().object_find(StringRef("b"), &b));
EXPECT_EQ(b.get_string(), StringRef("x"));
- const std::string array_json = R"([1,null,"x"])";
- auto old_array = legacy.parse(array_json.data(), array_json.size(),
config);
- ASSERT_TRUE(old_array.has_value());
- const auto& old_elements = old_array->values[0].get<TYPE_ARRAY>();
- ASSERT_EQ(old_elements.size(), 3);
- EXPECT_EQ(old_elements[0].get<TYPE_BIGINT>(), 1);
- EXPECT_TRUE(old_elements[1].is_null());
- EXPECT_EQ(old_elements[2].get<TYPE_STRING>(), "x");
- VariantField new_array_field = encode_json(array_json);
+ VariantField new_array_field = encode_json(R"([1,null,"x"])");
VariantRef new_array = new_array_field.ref();
ASSERT_EQ(new_array.num_elements(), 3);
EXPECT_EQ(new_array.array_at(0).get_int(), 1);
EXPECT_TRUE(new_array.array_at(1).is_null());
EXPECT_EQ(new_array.array_at(2).get_string(), StringRef("x"));
- auto old_empty_object = legacy.parse("{}", 2, config);
- ASSERT_TRUE(old_empty_object.has_value());
- EXPECT_TRUE(old_empty_object->paths.empty());
EXPECT_EQ(encode_json("{}").ref().num_elements(), 0);
-
- auto old_empty_array = legacy.parse("[]", 2, config);
- ASSERT_TRUE(old_empty_array.has_value());
- EXPECT_TRUE(old_empty_array->values[0].get<TYPE_ARRAY>().empty());
EXPECT_EQ(encode_json("[]").ref().num_elements(), 0);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]