This is an automated email from the ASF dual-hosted git repository.
mrhhsg 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 dc7b50ce99e [fix](be) Avoid unsigned underflow in JSON modify path
(#63579)
dc7b50ce99e is described below
commit dc7b50ce99ea5c1af6404c8d0dbc957bc51cba4a
Author: Jerry Hu <[email protected]>
AuthorDate: Mon Jun 8 09:08:58 2026 +0800
[fix](be) Avoid unsigned underflow in JSON modify path (#63579)
### What problem does this PR solve?
Issue Number: None
Problem Summary: JSON modify functions build a parent path by iterating
to the element before the last JSON path leg. The loop used
`get_leg_vector_size() - 1` on an unsigned size, which can underflow for
an empty path expression even though normal root-path execution resolves
to the root value before that branch. This patch caches the leg count
once, asserts the non-empty invariant for the insert-parent branch, and
uses `j + 1 < legs_count` to avoid unsigned subtraction while preserving
behavior.
The patch also adds BE unit coverage for missing-path JSONB modify cases
where the parent path has to be rebuilt, including single-leg object
insertion, nested object insertion, and array append behavior for both
`jsonb_insert` and `jsonb_set`.
### Release note
None
### Check List (For Author)
- Test:
- Unit Test: added `FunctionJsonbTEST.JsonbModifyMissingPathParent`
- Build check: `DORIS_HOME=/mnt/disk7/hushenggang/doris-fix-spill ninja
-C be/ut_build_ASAN
test/CMakeFiles/doris_be_test.dir/exprs/function/function_jsonb_test.cpp.o`
- Format check: `build-support/clang-format.sh`;
`build-support/check-format.sh`; `git diff --check`
- Behavior changed: No
- Does this need documentation: No
---
be/src/exprs/function/function_jsonb.cpp | 5 +++--
be/test/exprs/function/function_jsonb_test.cpp | 24 ++++++++++++++++++++++++
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/be/src/exprs/function/function_jsonb.cpp
b/be/src/exprs/function/function_jsonb.cpp
index 84238c6d688..3941a0a6fc7 100644
--- a/be/src/exprs/function/function_jsonb.cpp
+++ b/be/src/exprs/function/function_jsonb.cpp
@@ -2048,6 +2048,7 @@ public:
bool replace = false;
parents.emplace_back(json_documents[row_idx]->getValue());
+ const auto legs_count =
json_path[path_index].get_leg_vector_size();
if (find_result.value) {
// find target path, replace it with the new value.
replace = true;
@@ -2058,7 +2059,8 @@ public:
} else {
// does not find target path, insert the new value.
JsonbPath new_path;
- for (size_t j = 0; j <
json_path[path_index].get_leg_vector_size() - 1; ++j) {
+ DCHECK_GT(legs_count, 0);
+ for (size_t j = 0; j + 1 < legs_count; ++j) {
auto* current_leg =
json_path[path_index].get_leg_from_leg_vector(j);
std::unique_ptr<leg_info> leg =
std::make_unique<leg_info>(
current_leg->leg_ptr, current_leg->leg_len,
@@ -2072,7 +2074,6 @@ public:
}
}
- const auto legs_count =
json_path[path_index].get_leg_vector_size();
leg_info* last_leg =
legs_count > 0
?
json_path[path_index].get_leg_from_leg_vector(legs_count - 1)
diff --git a/be/test/exprs/function/function_jsonb_test.cpp
b/be/test/exprs/function/function_jsonb_test.cpp
index 25377a0bce9..8d9df92d402 100644
--- a/be/test/exprs/function/function_jsonb_test.cpp
+++ b/be/test/exprs/function/function_jsonb_test.cpp
@@ -986,4 +986,28 @@ TEST(FunctionJsonbTEST, JsonContains) {
ASSERT_TRUE(st.ok()) << "execute failed: " << st.to_string();
}
+TEST(FunctionJsonbTEST, JsonbModifyMissingPathParent) {
+ InputTypeSet input_types = {PrimitiveType::TYPE_JSONB,
PrimitiveType::TYPE_VARCHAR,
+ PrimitiveType::TYPE_JSONB};
+
+ {
+ DataSet data_set = {
+ {{STRING("{}"), STRING("$.a"), STRING("1")},
STRING(R"({"a":1})")},
+ {{STRING(R"({"a":{}})"), STRING("$.a.b"), STRING("2")},
STRING(R"({"a":{"b":2}})")},
+ {{STRING(R"({"a":[1]})"), STRING("$.a[1]"), STRING("2")},
STRING(R"({"a":[1,2]})")},
+ };
+ static_cast<void>(
+ check_function<DataTypeJsonb, true>("jsonb_insert",
input_types, data_set));
+ }
+
+ {
+ DataSet data_set = {
+ {{STRING("{}"), STRING("$.a"), STRING("1")},
STRING(R"({"a":1})")},
+ {{STRING(R"({"a":{}})"), STRING("$.a.b"), STRING("2")},
STRING(R"({"a":{"b":2}})")},
+ {{STRING(R"({"a":[1]})"), STRING("$.a[1]"), STRING("2")},
STRING(R"({"a":[1,2]})")},
+ };
+ static_cast<void>(check_function<DataTypeJsonb, true>("jsonb_set",
input_types, data_set));
+ }
+}
+
} // namespace doris
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]