diff --git a/be/src/vec/functions/function_json.cpp b/be/src/vec/functions/function_json.cpp index 508ade81e6..dae0cea227 100644 --- a/be/src/vec/functions/function_json.cpp +++ b/be/src/vec/functions/function_json.cpp @@ -815,7 +815,7 @@ struct FunctionJsonExtractImpl { } static void execute(const std::vector& data_columns, - ColumnString& result_column, size_t input_rows_count) { + ColumnString& result_column, NullMap& null_map, size_t input_rows_count) { rapidjson::Document document; rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); rapidjson::StringBuffer buf; @@ -835,11 +835,16 @@ struct FunctionJsonExtractImpl { } } - // write value as string - buf.Clear(); - writer.Reset(buf); - value.Accept(writer); - result_column.insert_data(buf.GetString(), buf.GetSize()); + if (value.IsNull()) { + null_map[row] = 1; + result_column.insert_default(); + } else { + // write value as string + buf.Clear(); + writer.Reset(buf); + value.Accept(writer); + result_column.insert_data(buf.GetString(), buf.GetSize()); + } } } }; @@ -880,6 +885,37 @@ public: } }; +template +class FunctionJsonNullable : public IFunction { +public: + static constexpr auto name = Impl::name; + static FunctionPtr create() { return std::make_shared>(); } + String get_name() const override { return name; } + size_t get_number_of_arguments() const override { return 0; } + bool is_variadic() const override { return true; } + bool use_default_implementation_for_constants() const override { return true; } + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { + return make_nullable(std::make_shared()); + } + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + size_t result, size_t input_rows_count) const override { + auto result_column = ColumnString::create(); + auto null_map = ColumnUInt8::create(input_rows_count, 0); + std::vector column_ptrs; // prevent converted column destruct + std::vector data_columns; + for (int i = 0; i < arguments.size(); i++) { + column_ptrs.push_back( + block.get_by_position(arguments[i]).column->convert_to_full_column_if_const()); + data_columns.push_back(assert_cast(column_ptrs.back().get())); + } + Impl::execute(data_columns, *assert_cast(result_column.get()), + null_map->get_data(), input_rows_count); + block.replace_by_position( + result, ColumnNullable::create(std::move(result_column), std::move(null_map))); + return Status::OK(); + } +}; + using FunctionGetJsonDouble = FunctionBinaryStringOperateToNullType; using FunctionGetJsonInt = FunctionBinaryStringOperateToNullType; using FunctionGetJsonBigInt = FunctionBinaryStringOperateToNullType; @@ -1476,7 +1512,7 @@ void register_function_json(SimpleFunctionFactory& factory) { factory.register_function>(); factory.register_function>(); factory.register_function>(); - factory.register_function>(); + factory.register_function>(); factory.register_function(); factory.register_function(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonExtract.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonExtract.java index 12d1c22a13..f7d1bd612c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonExtract.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/JsonExtract.java @@ -19,8 +19,8 @@ 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.AlwaysNullable; 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.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.VarcharType; import org.apache.doris.nereids.util.ExpressionUtils; @@ -34,7 +34,7 @@ import java.util.List; * ScalarFunction 'json_object'. This class is generated by GenerateFunction. */ public class JsonExtract extends ScalarFunction - implements ExplicitlyCastableSignature, PropagateNullable { + implements ExplicitlyCastableSignature, AlwaysNullable { public static final List SIGNATURES = ImmutableList.of(FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT) diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index d8bab55de0..23d86eedbd 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -1796,7 +1796,8 @@ visible_functions = { [['json_valid'], 'INT', ['VARCHAR'], 'ALWAYS_NULLABLE'], [['json_contains'], 'BOOLEAN', ['VARCHAR', 'VARCHAR', 'VARCHAR'], 'ALWAYS_NULLABLE'], [['json_unquote'], 'VARCHAR', ['VARCHAR'], 'ALWAYS_NULLABLE'], - [['json_extract'], 'VARCHAR', ['VARCHAR', 'VARCHAR', '...'], ''], + [['json_extract'], 'VARCHAR', ['VARCHAR', 'VARCHAR', '...'], 'ALWAYS_NULLABLE'], + [['json_extract'], 'STRING', ['STRING', 'STRING', '...'], 'ALWAYS_NULLABLE'], [['json_insert'], 'VARCHAR', ['VARCHAR', 'VARCHAR', '...'], ''], [['json_replace'], 'VARCHAR', ['VARCHAR', 'VARCHAR', '...'], ''], [['json_set'], 'VARCHAR', ['VARCHAR', 'VARCHAR', '...'], ''] diff --git a/regression-test/data/json_p0/test_json_load_and_function.out b/regression-test/data/json_p0/test_json_load_and_function.out index 5fdb5342cb..e12fb79e38 100644 --- a/regression-test/data/json_p0/test_json_load_and_function.out +++ b/regression-test/data/json_p0/test_json_load_and_function.out @@ -5539,29 +5539,29 @@ false -- !select -- 1 \N \N -2 null null -3 true null -4 false null -5 100 null -6 10000 null -7 1000000000 null -8 1152921504606846976 null -9 6.18 null -10 "abcd" null -11 {} null +2 null \N +3 true \N +4 false \N +5 100 \N +6 10000 \N +7 1000000000 \N +8 1152921504606846976 \N +9 6.18 \N +10 "abcd" \N +11 {} \N 12 {"k1":"v31","k2":300} "v31" -13 [] null -14 [123,456] null -15 ["abc","def"] null -16 [null,true,false,100,6.18,"abc"] null +13 [] \N +14 [123,456] \N +15 ["abc","def"] \N +16 [null,true,false,100,6.18,"abc"] \N 17 [{"k1":"v41","k2":400},1,"a",3.14] ["v41"] 18 {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]} "v31" 26 \N \N 27 {"k1":"v1","k2":200} "v1" -28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} null -29 12524337771678448270 null -30 -9223372036854775808 null -31 18446744073709551615 null +28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} \N +29 12524337771678448270 \N +30 -9223372036854775808 \N +31 18446744073709551615 \N -- !select -- 1 \N \N 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 29cb48477a..215f798df9 100644 --- a/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out +++ b/regression-test/data/jsonb_p0/test_jsonb_load_and_function.out @@ -7333,29 +7333,29 @@ false -- !select -- 1 \N \N -2 null null -3 true null -4 false null -5 100 null -6 10000 null -7 1000000000 null -8 1152921504606846976 null -9 6.18 null -10 "abcd" null -11 {} null +2 null \N +3 true \N +4 false \N +5 100 \N +6 10000 \N +7 1000000000 \N +8 1152921504606846976 \N +9 6.18 \N +10 "abcd" \N +11 {} \N 12 {"k1":"v31","k2":300} "v31" -13 [] null -14 [123,456] null -15 ["abc","def"] null -16 [null,true,false,100,6.18,"abc"] null +13 [] \N +14 [123,456] \N +15 ["abc","def"] \N +16 [null,true,false,100,6.18,"abc"] \N 17 [{"k1":"v41","k2":400},1,"a",3.14] ["v41"] 18 {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]} "v31" 26 \N \N 27 {"k1":"v1","k2":200} "v1" -28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} null -29 12524337771678448270 null -30 -9223372036854775808 null -31 18446744073709551615 null +28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} \N +29 12524337771678448270 \N +30 -9223372036854775808 \N +31 18446744073709551615 \N -- !select -- 1 \N \N diff --git a/regression-test/data/nereids_function_p0/scalar_function/J.out b/regression-test/data/nereids_function_p0/scalar_function/J.out index dbcacdc0f1..5785ef0c48 100644 --- a/regression-test/data/nereids_function_p0/scalar_function/J.out +++ b/regression-test/data/nereids_function_p0/scalar_function/J.out @@ -7333,29 +7333,29 @@ false -- !select -- 1 \N \N -2 null null -3 true null -4 false null -5 100 null -6 10000 null -7 1000000000 null -8 1152921504606846976 null -9 6.18 null -10 "abcd" null -11 {} null +2 null \N +3 true \N +4 false \N +5 100 \N +6 10000 \N +7 1000000000 \N +8 1152921504606846976 \N +9 6.18 \N +10 "abcd" \N +11 {} \N 12 {"k1":"v31","k2":300} "v31" -13 [] null -14 [123,456] null -15 ["abc","def"] null -16 [null,true,false,100,6.18,"abc"] null +13 [] \N +14 [123,456] \N +15 ["abc","def"] \N +16 [null,true,false,100,6.18,"abc"] \N 17 [{"k1":"v41","k2":400},1,"a",3.14] ["v41"] 18 {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]} "v31" 26 \N \N 27 {"k1":"v1","k2":200} "v1" -28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} null -29 12524337771678448270 null -30 -9223372036854775808 null -31 18446744073709551615 null +28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} \N +29 12524337771678448270 \N +30 -9223372036854775808 \N +31 18446744073709551615 \N -- !select -- 1 \N \N diff --git a/regression-test/data/nereids_p0/json_p0/test_json_load_and_function.out b/regression-test/data/nereids_p0/json_p0/test_json_load_and_function.out index 5fdb5342cb..e12fb79e38 100644 --- a/regression-test/data/nereids_p0/json_p0/test_json_load_and_function.out +++ b/regression-test/data/nereids_p0/json_p0/test_json_load_and_function.out @@ -5539,29 +5539,29 @@ false -- !select -- 1 \N \N -2 null null -3 true null -4 false null -5 100 null -6 10000 null -7 1000000000 null -8 1152921504606846976 null -9 6.18 null -10 "abcd" null -11 {} null +2 null \N +3 true \N +4 false \N +5 100 \N +6 10000 \N +7 1000000000 \N +8 1152921504606846976 \N +9 6.18 \N +10 "abcd" \N +11 {} \N 12 {"k1":"v31","k2":300} "v31" -13 [] null -14 [123,456] null -15 ["abc","def"] null -16 [null,true,false,100,6.18,"abc"] null +13 [] \N +14 [123,456] \N +15 ["abc","def"] \N +16 [null,true,false,100,6.18,"abc"] \N 17 [{"k1":"v41","k2":400},1,"a",3.14] ["v41"] 18 {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]} "v31" 26 \N \N 27 {"k1":"v1","k2":200} "v1" -28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} null -29 12524337771678448270 null -30 -9223372036854775808 null -31 18446744073709551615 null +28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} \N +29 12524337771678448270 \N +30 -9223372036854775808 \N +31 18446744073709551615 \N -- !select -- 1 \N \N diff --git a/regression-test/data/nereids_p0/jsonb_p0/test_jsonb_load_and_function.out b/regression-test/data/nereids_p0/jsonb_p0/test_jsonb_load_and_function.out index fa10d72000..8e77ddb11c 100644 --- a/regression-test/data/nereids_p0/jsonb_p0/test_jsonb_load_and_function.out +++ b/regression-test/data/nereids_p0/jsonb_p0/test_jsonb_load_and_function.out @@ -7333,29 +7333,29 @@ false -- !select -- 1 \N \N -2 null null -3 true null -4 false null -5 100 null -6 10000 null -7 1000000000 null -8 1152921504606846976 null -9 6.18 null -10 "abcd" null -11 {} null +2 null \N +3 true \N +4 false \N +5 100 \N +6 10000 \N +7 1000000000 \N +8 1152921504606846976 \N +9 6.18 \N +10 "abcd" \N +11 {} \N 12 {"k1":"v31","k2":300} "v31" -13 [] null -14 [123,456] null -15 ["abc","def"] null -16 [null,true,false,100,6.18,"abc"] null +13 [] \N +14 [123,456] \N +15 ["abc","def"] \N +16 [null,true,false,100,6.18,"abc"] \N 17 [{"k1":"v41","k2":400},1,"a",3.14] ["v41"] 18 {"k1":"v31","k2":300,"a1":[{"k1":"v41","k2":400},1,"a",3.14]} "v31" 26 \N \N 27 {"k1":"v1","k2":200} "v1" -28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} null -29 12524337771678448270 null -30 -9223372036854775808 null -31 18446744073709551615 null +28 {"a.b.c":{"k1.a1":"v31","k2":300},"a":"niu"} \N +29 12524337771678448270 \N +30 -9223372036854775808 \N +31 18446744073709551615 \N -- !select -- 1 \N \N