From 2a5949cb9eded7984c52737a8929e3a3e8f4d782 Mon Sep 17 00:00:00 2001 From: Mryange <59914473+Mryange@users.noreply.github.com> Date: Sat, 11 May 2024 20:21:26 +0800 Subject: [PATCH] [fix](function) json_object can not input null value (#34591) (#34700) --- be/src/vec/functions/function_json.cpp | 25 ++++++++++++++++++- .../test_query_json_object.groovy | 4 +++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/be/src/vec/functions/function_json.cpp b/be/src/vec/functions/function_json.cpp index 8bfb8b35f2207c..3dcc94691ef20b 100644 --- a/be/src/vec/functions/function_json.cpp +++ b/be/src/vec/functions/function_json.cpp @@ -42,6 +42,7 @@ #include "common/compiler_util.h" // IWYU pragma: keep #include "common/status.h" #include "exprs/json_functions.h" +#include "util/simd/bits.h" #include "vec/io/io_helper.h" #ifdef __AVX2__ #include "util/jsonb_parser_simd.h" @@ -619,6 +620,7 @@ struct ExecuteReducer { struct FunctionJsonArrayImpl { static constexpr auto name = "json_array"; + static constexpr auto must_not_null = false; template using Reducer = ExecuteReducer; @@ -654,7 +656,7 @@ struct FunctionJsonArrayImpl { struct FunctionJsonObjectImpl { static constexpr auto name = "json_object"; - + static constexpr auto must_not_null = true; template using Reducer = ExecuteReducer; @@ -743,6 +745,9 @@ class FunctionJsonAlwaysNotNullable : public IFunction { data_columns.push_back(assert_cast(column_ptrs.back().get())); } } + if (SpecificImpl::must_not_null) { + RETURN_IF_ERROR(check_keys_all_not_null(nullmaps, input_rows_count, arguments.size())); + } execute(data_columns, *assert_cast(result_column.get()), input_rows_count, nullmaps); block.get_by_position(result).column = std::move(result_column); @@ -774,6 +779,24 @@ class FunctionJsonAlwaysNotNullable : public IFunction { result_column.insert_data(buf.GetString(), buf.GetSize()); } } + + static Status check_keys_all_not_null(const std::vector& nullmaps, int size, + size_t args) { + for (int i = 0; i < args; i += 2) { + const auto* null_map = nullmaps[i]; + if (null_map) { + const bool not_null_num = + simd::count_zero_num((int8_t*)null_map->get_data().data(), size); + if (not_null_num < size) { + return Status::InternalError( + "function {} can not input null value , JSON documents may not contain " + "NULL member names.", + name); + } + } + } + return Status::OK(); + } }; struct FunctionJsonQuoteImpl { diff --git a/regression-test/suites/query_p0/sql_functions/json_function/test_query_json_object.groovy b/regression-test/suites/query_p0/sql_functions/json_function/test_query_json_object.groovy index 2a12d69ffe0bc2..c3b1e35b5e663a 100644 --- a/regression-test/suites/query_p0/sql_functions/json_function/test_query_json_object.groovy +++ b/regression-test/suites/query_p0/sql_functions/json_function/test_query_json_object.groovy @@ -41,5 +41,9 @@ suite("test_query_json_object", "query") { sql "insert into ${tableName} values(4,null,null,'test','2022-01-01 11:11:11');" sql "insert into ${tableName} values(5,1,true,'test','2022-01-01 11:11:11');" qt_sql1 "select json_object('k0',k0,'k1',k1,'k2',k2,'k3',k3,'k4',k4,'k5', null,'k6','k6') from ${tableName} order by k0;" + test { + sql """select k0,json_object(k3,123) from ${tableName} order by k0;""" + exception "function json_object can not input null value , JSON documents may not contain NULL member names." + } sql "DROP TABLE ${tableName};" }