Coverage Report

Created: 2026-04-02 21:33

/root/doris/be/src/exprs/json_functions.h
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <fmt/format.h>
21
#include <rapidjson/document.h>
22
#include <simdjson.h> // IWYU pragma: keep
23
24
#include <sstream>
25
#include <string>
26
#include <utility>
27
#include <vector>
28
29
#include "common/status.h"
30
31
namespace simdjson {
32
namespace fallback {
33
namespace ondemand {
34
class object;
35
class value;
36
} // namespace ondemand
37
} // namespace fallback
38
} // namespace simdjson
39
40
namespace doris {
41
42
enum JsonFunctionType {
43
    JSON_FUN_INT = 0,
44
    JSON_FUN_DOUBLE,
45
    JSON_FUN_STRING,
46
47
    JSON_FUN_UNKNOWN //The last
48
};
49
50
struct JsonPath {
51
    std::string key;               // key of a json object
52
    int idx;                       // array index of a json array, -1 means not set, -2 means *
53
    bool is_valid;                 // true if the path is successfully parsed
54
    bool is_reverse_index = false; // true if the path is last index, like '$.a[LAST(1)]'
55
56
    JsonPath(std::string key_, int idx_, bool is_valid_, bool is_reverse_index_)
57
            : key(std::move(key_)),
58
              idx(idx_),
59
              is_valid(is_valid_),
60
54
              is_reverse_index(is_reverse_index_) {}
61
62
    JsonPath(std::string key_, int idx_, bool is_valid_)
63
36
            : JsonPath(std::move(key_), idx_, is_valid_, false) {}
64
65
0
    std::string to_string() const {
66
0
        std::stringstream ss;
67
0
        if (!is_valid) {
68
0
            return "INVALID";
69
0
        }
70
0
        if (!key.empty()) {
71
0
            ss << key;
72
0
        }
73
0
        if (idx == -2) {
74
0
            ss << "[*]";
75
0
        } else if (is_reverse_index) {
76
0
            if (idx > 0) {
77
0
                ss << "[last-" << idx << "]";
78
0
            } else {
79
0
                ss << "[last]";
80
0
            }
81
0
        } else if (idx > -1) {
82
0
            ss << "[" << idx << "]";
83
0
        }
84
0
        return ss.str();
85
0
    }
86
87
0
    std::string debug_string() const {
88
0
        return fmt::format("key:{}, idx:{}, valid:{}, is_reverse_index:{}", key, idx, is_valid,
89
0
                           is_reverse_index);
90
0
    }
91
};
92
93
class JsonFunctions {
94
public:
95
    /**
96
     * The `document` parameter must be has parsed.
97
     * return Value Is Array object
98
     * wrap_explicitly is set to true when the returned Array is wrapped actively.
99
     */
100
    static rapidjson::Value* get_json_array_from_parsed_json(
101
            const std::vector<JsonPath>& parsed_paths, rapidjson::Value* document,
102
            rapidjson::Document::AllocatorType& mem_allocator, bool* wrap_explicitly);
103
104
    // this is only for test, it will parse the json path inside,
105
    // so that we can easily pass a json path as string.
106
    static rapidjson::Value* get_json_array_from_parsed_json(
107
            const std::string& jsonpath, rapidjson::Value* document,
108
            rapidjson::Document::AllocatorType& mem_allocator, bool* wrap_explicitly);
109
110
    static rapidjson::Value* get_json_object_from_parsed_json(
111
            const std::vector<JsonPath>& parsed_paths, rapidjson::Value* document,
112
            rapidjson::Document::AllocatorType& mem_allocator);
113
114
    static void parse_json_paths(const std::string& path_strings,
115
                                 std::vector<JsonPath>* parsed_paths);
116
    // extract_from_object extracts value from object according to the json path.
117
    // Now, we do not support complete functions of json path.
118
    // Eg. city[*].id is not supported in this function
119
    static Status extract_from_object(simdjson::ondemand::object& obj,
120
                                      const std::vector<JsonPath>& jsonpath,
121
                                      simdjson::ondemand::value* value) noexcept;
122
    // src:    {"a" : "b" {"c" : 1}, "e" : 123}
123
    // dst:    {"a" : "b" {"d" : 1}}
124
    // merged: {"a" : "b" : {"c" : 1, "d" : 1}, "e" : 123}
125
    static void merge_objects(rapidjson::Value& dst_object, rapidjson::Value& src_object,
126
                              rapidjson::Document::AllocatorType& allocator);
127
128
    static std::string print_json_value(const rapidjson::Value& value);
129
130
    static bool is_root_path(const std::vector<JsonPath>& json_path);
131
132
private:
133
    static rapidjson::Value* match_value(const std::vector<JsonPath>& parsed_paths,
134
                                         rapidjson::Value* document,
135
                                         rapidjson::Document::AllocatorType& mem_allocator,
136
                                         bool is_insert_null = false);
137
    static void get_parsed_paths(const std::vector<std::string>& path_exprs,
138
                                 std::vector<JsonPath>* parsed_paths);
139
};
140
} // namespace doris