This is an automated email from the ASF dual-hosted git repository.
dataroaring pushed a commit to branch branch-3.0
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.0 by this push:
new d7cbe470ac9 [fix](json) incorrect results of json_contains (#53291)
(#53364)
d7cbe470ac9 is described below
commit d7cbe470ac9c92c4cb4c96534b34d1f5ea585755
Author: Jerry Hu <[email protected]>
AuthorDate: Thu Jul 17 13:21:51 2025 +0800
[fix](json) incorrect results of json_contains (#53291) (#53364)
Fix the incorrect results and remove unused code.
Pick: #53291
---
be/src/util/jsonb_document.h | 12 +-
be/src/vec/functions/function_json.cpp | 132 ---------------------
.../data/jsonb_p0/test_jsonb_load_and_function.out | Bin 188934 -> 188939 bytes
.../test_jsonb_load_unique_key_and_function.out | Bin 124394 -> 124396 bytes
.../json_functions/test_json_function.out | Bin 1476 -> 1644 bytes
.../json_functions/test_json_function.groovy | 19 +++
6 files changed, 25 insertions(+), 138 deletions(-)
diff --git a/be/src/util/jsonb_document.h b/be/src/util/jsonb_document.h
index 7f50c4012ba..6d269f6dd52 100644
--- a/be/src/util/jsonb_document.h
+++ b/be/src/util/jsonb_document.h
@@ -1326,12 +1326,12 @@ inline bool JsonbValue::contains(JsonbValue* rhs) const
{
}
case JsonbType::T_Object: {
if (rhs->isObject()) {
- auto* str_value1 = (ObjectVal*)this;
- auto* str_value2 = (ObjectVal*)rhs;
- for (int i = 0; i < str_value2->numElem(); ++i) {
- JsonbKeyValue* key = str_value2->getJsonbKeyValue(i);
- JsonbValue* value = str_value1->find(key->getKeyStr(),
key->klen());
- if (key != nullptr && value != nullptr &&
!value->contains(key->value())) {
+ const auto* obj_value1 = (ObjectVal*)this;
+ const auto* obj_value2 = (ObjectVal*)rhs;
+ for (int i = 0; i < obj_value2->numElem(); ++i) {
+ JsonbKeyValue* key = obj_value2->getJsonbKeyValue(i);
+ JsonbValue* value = obj_value1->find(key->getKeyStr(),
key->klen());
+ if (value == nullptr || !value->contains(key->value())) {
return false;
}
}
diff --git a/be/src/vec/functions/function_json.cpp
b/be/src/vec/functions/function_json.cpp
index ab1ff616f2b..7ce4049249d 100644
--- a/be/src/vec/functions/function_json.cpp
+++ b/be/src/vec/functions/function_json.cpp
@@ -1105,137 +1105,6 @@ public:
}
};
-class FunctionJsonContains : public IFunction {
-public:
- static constexpr auto name = "json_contains";
- static FunctionPtr create() { return
std::make_shared<FunctionJsonContains>(); }
-
- String get_name() const override { return name; }
-
- size_t get_number_of_arguments() const override { return 3; }
-
- DataTypePtr get_return_type_impl(const DataTypes& arguments) const
override {
- return make_nullable(std::make_shared<DataTypeUInt8>());
- }
-
- DataTypes get_variadic_argument_types_impl() const override {
- return {std::make_shared<DataTypeString>(),
std::make_shared<DataTypeString>(),
- std::make_shared<DataTypeString>()};
- }
-
- bool use_default_implementation_for_nulls() const override { return false;
}
-
- bool json_contains_object(const rapidjson::Value& target,
- const rapidjson::Value& search_value) const {
- if (!target.IsObject() || !search_value.IsObject()) {
- return false;
- }
-
- for (auto itr = search_value.MemberBegin(); itr !=
search_value.MemberEnd(); ++itr) {
- if (!target.HasMember(itr->name) ||
!json_contains(target[itr->name], itr->value)) {
- return false;
- }
- }
-
- return true;
- }
-
- bool json_contains_array(const rapidjson::Value& target,
- const rapidjson::Value& search_value) const {
- if (!target.IsArray() || !search_value.IsArray()) {
- return false;
- }
-
- for (auto itr = search_value.Begin(); itr != search_value.End();
++itr) {
- bool found = false;
- for (auto target_itr = target.Begin(); target_itr != target.End();
++target_itr) {
- if (json_contains(*target_itr, *itr)) {
- found = true;
- break;
- }
- }
- if (!found) {
- return false;
- }
- }
-
- return true;
- }
-
- bool json_contains(const rapidjson::Value& target, const rapidjson::Value&
search_value) const {
- if (target == search_value) {
- return true;
- }
-
- if (target.IsObject() && search_value.IsObject()) {
- return json_contains_object(target, search_value);
- }
-
- if (target.IsArray() && search_value.IsArray()) {
- return json_contains_array(target, search_value);
- }
-
- return false;
- }
-
- Status execute_impl(FunctionContext* context, Block& block, const
ColumnNumbers& arguments,
- size_t result, size_t input_rows_count) const override
{
- const IColumn& col_json =
*(block.get_by_position(arguments[0]).column);
- const IColumn& col_search =
*(block.get_by_position(arguments[1]).column);
- const IColumn& col_path =
*(block.get_by_position(arguments[2]).column);
-
- auto null_map = ColumnUInt8::create(input_rows_count, 0);
-
- const ColumnString* col_json_string =
check_and_get_column<ColumnString>(col_json);
- const ColumnString* col_search_string =
check_and_get_column<ColumnString>(col_search);
- const ColumnString* col_path_string =
check_and_get_column<ColumnString>(col_path);
-
- if (!col_json_string || !col_search_string || !col_path_string) {
- return Status::RuntimeError("Illegal column should be
ColumnString");
- }
-
- auto col_to = ColumnVector<vectorized::UInt8>::create();
- auto& vec_to = col_to->get_data();
- size_t size = col_json.size();
- vec_to.resize(size);
-
- for (size_t i = 0; i < input_rows_count; ++i) {
- if (col_json.is_null_at(i) || col_search.is_null_at(i) ||
col_path.is_null_at(i)) {
- null_map->get_data()[i] = 1;
- vec_to[i] = 0;
- continue;
- }
-
- const auto& json_val = col_json_string->get_data_at(i);
- const auto& search_val = col_search_string->get_data_at(i);
- const auto& path_val = col_path_string->get_data_at(i);
-
- std::string_view json_string(json_val.data, json_val.size);
- std::string_view search_string(search_val.data, search_val.size);
- std::string_view path_string(path_val.data, path_val.size);
-
- rapidjson::Document document;
- auto target_val = get_json_object<JSON_FUN_STRING>(json_string,
path_string, &document);
- if (target_val == nullptr || target_val->IsNull()) {
- vec_to[i] = 0;
- } else {
- rapidjson::Document search_doc;
- search_doc.Parse(search_string.data(), search_string.size());
- if (json_contains(*target_val, search_doc)) {
- vec_to[i] = 1;
- } else {
- vec_to[i] = 0;
- }
- }
- }
-
- block.replace_by_position(result,
- ColumnNullable::create(std::move(col_to),
std::move(null_map)));
-
- return Status::OK();
- }
-};
-
class FunctionJsonUnquote : public IFunction {
public:
static constexpr auto name = "json_unquote";
@@ -1658,7 +1527,6 @@ void register_function_json(SimpleFunctionFactory&
factory) {
FunctionJsonNullable<FunctionJsonExtractImpl<JsonExtractNoQuotesName, true>>>();
factory.register_function<FunctionJsonValid>();
- factory.register_function<FunctionJsonContains>();
factory.register_function<FunctionJsonModifyImpl<FunctionJsonInsert>>();
factory.register_function<FunctionJsonModifyImpl<FunctionJsonReplace>>();
diff --git a/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out
b/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out
index d7d7611931f..a27fa14581f 100644
Binary files a/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out
and b/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out differ
diff --git
a/regression-test/data/jsonb_p0/test_jsonb_load_unique_key_and_function.out
b/regression-test/data/jsonb_p0/test_jsonb_load_unique_key_and_function.out
index 427b6426d68..36d14661668 100644
Binary files
a/regression-test/data/jsonb_p0/test_jsonb_load_unique_key_and_function.out and
b/regression-test/data/jsonb_p0/test_jsonb_load_unique_key_and_function.out
differ
diff --git
a/regression-test/data/query_p0/sql_functions/json_functions/test_json_function.out
b/regression-test/data/query_p0/sql_functions/json_functions/test_json_function.out
index c22acc17134..47da4ec2bbe 100644
Binary files
a/regression-test/data/query_p0/sql_functions/json_functions/test_json_function.out
and
b/regression-test/data/query_p0/sql_functions/json_functions/test_json_function.out
differ
diff --git
a/regression-test/suites/query_p0/sql_functions/json_functions/test_json_function.groovy
b/regression-test/suites/query_p0/sql_functions/json_functions/test_json_function.groovy
index fe4dfc55315..517db385cc2 100644
---
a/regression-test/suites/query_p0/sql_functions/json_functions/test_json_function.groovy
+++
b/regression-test/suites/query_p0/sql_functions/json_functions/test_json_function.groovy
@@ -91,4 +91,23 @@ suite("test_json_function", "arrow_flight_sql") {
qt_sql """select get_json_string('{"name\\k" : 123}', '\$.name\\k')"""
qt_sql """select get_json_string('{"name\\k" : 123}', '\$.name\\\\k')"""
qt_sql """select get_json_string('{"name\\k" : 123}', '\$.name\\\\\\k')"""
+
+ qt_json_contains1 """
+ SELECT JSON_CONTAINS('{"age": 30, "name": "John", "hobbies": ["reading",
"swimming"]}', '{"invalid": "format"}');
+ """
+ qt_json_contains2 """
+ SELECT JSON_CONTAINS('{"age": 25, "name": "Alice", "hobbies":
["painting", "music"]}', '{"age": 25}');
+ """
+ qt_json_contains3 """
+ SELECT JSON_CONTAINS('{"age": 25, "name": "Alice", "hobbies":
["painting", "music"]}', '{"age": "25"}');
+ """
+ qt_json_contains4 """
+ SELECT JSON_CONTAINS('{"age": 25, "name": "Alice", "hobbies":
["painting", "music"]}', '"music"', '\$.hobbies[1]');
+ """
+ qt_json_contains5 """
+ SELECT JSON_CONTAINS('{"age": 25, "name": "Alice", "hobbies":
["painting", "music"]}', '"music"', '\$.hobbies[0]');
+ """
+ qt_json_contains6 """
+ SELECT JSON_CONTAINS(NULL, '"music"', '{"age": 25}');
+ """
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]