Coverage Report

Created: 2026-07-14 14:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/variant/variant_jsonb.cpp
Line
Count
Source
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
#include "util/variant/variant_jsonb.h"
19
20
#include <array>
21
#include <cstdint>
22
#include <cstring>
23
#include <limits>
24
25
#include "common/exception.h"
26
#include "core/types.h"
27
#include "util/jsonb_document.h"
28
#include "util/jsonb_writer.h"
29
#include "util/variant/variant_builder.h"
30
#include "util/variant/variant_encoding.h"
31
32
namespace doris {
33
namespace {
34
35
static_assert(MaxNestingLevel <= VARIANT_MAX_NESTING_DEPTH);
36
37
class BoundedJsonbCursor {
38
public:
39
607
    BoundedJsonbCursor(const char* data, size_t size) : _current(data), _remaining(size) {}
40
41
    template <typename T>
42
1.83k
    T read(const char* description) {
43
1.83k
        require(sizeof(T), description);
44
1.83k
        T value;
45
1.83k
        std::memcpy(&value, _current, sizeof(T));
46
1.83k
        _current += sizeof(T);
47
1.83k
        _remaining -= sizeof(T);
48
1.83k
        return value;
49
1.83k
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readIhEET_PKc
Line
Count
Source
42
952
    T read(const char* description) {
43
952
        require(sizeof(T), description);
44
952
        T value;
45
952
        std::memcpy(&value, _current, sizeof(T));
46
952
        _current += sizeof(T);
47
952
        _remaining -= sizeof(T);
48
952
        return value;
49
952
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readIaEET_PKc
Line
Count
Source
42
8
    T read(const char* description) {
43
8
        require(sizeof(T), description);
44
8
        T value;
45
8
        std::memcpy(&value, _current, sizeof(T));
46
8
        _current += sizeof(T);
47
8
        _remaining -= sizeof(T);
48
8
        return value;
49
8
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readIsEET_PKc
Line
Count
Source
42
5
    T read(const char* description) {
43
5
        require(sizeof(T), description);
44
5
        T value;
45
5
        std::memcpy(&value, _current, sizeof(T));
46
5
        _current += sizeof(T);
47
5
        _remaining -= sizeof(T);
48
5
        return value;
49
5
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readIiEET_PKc
Line
Count
Source
42
19
    T read(const char* description) {
43
19
        require(sizeof(T), description);
44
19
        T value;
45
19
        std::memcpy(&value, _current, sizeof(T));
46
19
        _current += sizeof(T);
47
19
        _remaining -= sizeof(T);
48
19
        return value;
49
19
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readIlEET_PKc
Line
Count
Source
42
28
    T read(const char* description) {
43
28
        require(sizeof(T), description);
44
28
        T value;
45
28
        std::memcpy(&value, _current, sizeof(T));
46
28
        _current += sizeof(T);
47
28
        _remaining -= sizeof(T);
48
28
        return value;
49
28
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readIdEET_PKc
Line
Count
Source
42
10
    T read(const char* description) {
43
10
        require(sizeof(T), description);
44
10
        T value;
45
10
        std::memcpy(&value, _current, sizeof(T));
46
10
        _current += sizeof(T);
47
10
        _remaining -= sizeof(T);
48
10
        return value;
49
10
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readIjEET_PKc
Line
Count
Source
42
686
    T read(const char* description) {
43
686
        require(sizeof(T), description);
44
686
        T value;
45
686
        std::memcpy(&value, _current, sizeof(T));
46
686
        _current += sizeof(T);
47
686
        _remaining -= sizeof(T);
48
686
        return value;
49
686
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readItEET_PKc
Line
Count
Source
42
2
    T read(const char* description) {
43
2
        require(sizeof(T), description);
44
2
        T value;
45
2
        std::memcpy(&value, _current, sizeof(T));
46
2
        _current += sizeof(T);
47
2
        _remaining -= sizeof(T);
48
2
        return value;
49
2
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readInEET_PKc
Line
Count
Source
42
50
    T read(const char* description) {
43
50
        require(sizeof(T), description);
44
50
        T value;
45
50
        std::memcpy(&value, _current, sizeof(T));
46
50
        _current += sizeof(T);
47
50
        _remaining -= sizeof(T);
48
50
        return value;
49
50
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readIfEET_PKc
Line
Count
Source
42
6
    T read(const char* description) {
43
6
        require(sizeof(T), description);
44
6
        T value;
45
6
        std::memcpy(&value, _current, sizeof(T));
46
6
        _current += sizeof(T);
47
6
        _remaining -= sizeof(T);
48
6
        return value;
49
6
    }
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_118BoundedJsonbCursor4readIN4wide7integerILm256EiEEEET_PKc
Line
Count
Source
42
73
    T read(const char* description) {
43
73
        require(sizeof(T), description);
44
73
        T value;
45
73
        std::memcpy(&value, _current, sizeof(T));
46
73
        _current += sizeof(T);
47
73
        _remaining -= sizeof(T);
48
73
        return value;
49
73
    }
50
51
379
    StringRef read_bytes(size_t size, const char* description) {
52
379
        require(size, description);
53
379
        const StringRef result {_current, size};
54
379
        _current += size;
55
379
        _remaining -= size;
56
379
        return result;
57
379
    }
58
59
341
    BoundedJsonbCursor read_region(size_t size, const char* description) {
60
341
        const StringRef region = read_bytes(size, description);
61
341
        return {region.data, region.size};
62
341
    }
63
64
532
    bool empty() const noexcept { return _remaining == 0; }
65
1
    size_t remaining() const noexcept { return _remaining; }
66
67
private:
68
2.21k
    void require(size_t size, const char* description) const {
69
2.21k
        if (_remaining < size) {
70
225
            throw Exception(ErrorCode::CORRUPTION,
71
225
                            "Truncated JSONB while reading {}: need {} bytes, have {}", description,
72
225
                            size, _remaining);
73
225
        }
74
2.21k
    }
75
76
    const char* _current;
77
    size_t _remaining;
78
};
79
80
template <typename Integer>
81
35
uint32_t decimal_digits(Integer value) {
82
35
    uint32_t digits = 0;
83
456
    do {
84
456
        value /= 10;
85
456
        ++digits;
86
456
    } while (value != 0);
87
35
    return digits;
88
35
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_114decimal_digitsInEEjT_
Line
Count
Source
81
18
uint32_t decimal_digits(Integer value) {
82
18
    uint32_t digits = 0;
83
175
    do {
84
175
        value /= 10;
85
175
        ++digits;
86
175
    } while (value != 0);
87
18
    return digits;
88
18
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_114decimal_digitsIiEEjT_
Line
Count
Source
81
5
uint32_t decimal_digits(Integer value) {
82
5
    uint32_t digits = 0;
83
11
    do {
84
11
        value /= 10;
85
11
        ++digits;
86
11
    } while (value != 0);
87
5
    return digits;
88
5
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_114decimal_digitsIlEEjT_
Line
Count
Source
81
5
uint32_t decimal_digits(Integer value) {
82
5
    uint32_t digits = 0;
83
27
    do {
84
27
        value /= 10;
85
27
        ++digits;
86
27
    } while (value != 0);
87
5
    return digits;
88
5
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_114decimal_digitsIN4wide7integerILm256EiEEEEjT_
Line
Count
Source
81
7
uint32_t decimal_digits(Integer value) {
82
7
    uint32_t digits = 0;
83
243
    do {
84
243
        value /= 10;
85
243
        ++digits;
86
243
    } while (value != 0);
87
7
    return digits;
88
7
}
89
90
template <typename Integer>
91
void require_decimal(Integer value, uint32_t precision, uint32_t scale, uint32_t maximum_precision,
92
46
                     uint32_t maximum_scale, const char* description) {
93
46
    if (precision == 0 || precision > maximum_precision) {
94
7
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} precision {} is outside [1, {}]",
95
7
                        description, precision, maximum_precision);
96
7
    }
97
39
    if (scale > maximum_scale) {
98
4
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} scale {} exceeds {}", description, scale,
99
4
                        maximum_scale);
100
4
    }
101
35
    const uint32_t digits = decimal_digits(value);
102
35
    if (digits > precision) {
103
6
        throw Exception(ErrorCode::CORRUPTION,
104
6
                        "JSONB {} value has {} digits but declared precision is {}", description,
105
6
                        digits, precision);
106
6
    }
107
35
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_115require_decimalInEEvT_jjjjPKc
Line
Count
Source
92
21
                     uint32_t maximum_scale, const char* description) {
93
21
    if (precision == 0 || precision > maximum_precision) {
94
2
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} precision {} is outside [1, {}]",
95
2
                        description, precision, maximum_precision);
96
2
    }
97
19
    if (scale > maximum_scale) {
98
1
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} scale {} exceeds {}", description, scale,
99
1
                        maximum_scale);
100
1
    }
101
18
    const uint32_t digits = decimal_digits(value);
102
18
    if (digits > precision) {
103
2
        throw Exception(ErrorCode::CORRUPTION,
104
2
                        "JSONB {} value has {} digits but declared precision is {}", description,
105
2
                        digits, precision);
106
2
    }
107
18
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_115require_decimalIiEEvT_jjjjPKc
Line
Count
Source
92
8
                     uint32_t maximum_scale, const char* description) {
93
8
    if (precision == 0 || precision > maximum_precision) {
94
2
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} precision {} is outside [1, {}]",
95
2
                        description, precision, maximum_precision);
96
2
    }
97
6
    if (scale > maximum_scale) {
98
1
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} scale {} exceeds {}", description, scale,
99
1
                        maximum_scale);
100
1
    }
101
5
    const uint32_t digits = decimal_digits(value);
102
5
    if (digits > precision) {
103
1
        throw Exception(ErrorCode::CORRUPTION,
104
1
                        "JSONB {} value has {} digits but declared precision is {}", description,
105
1
                        digits, precision);
106
1
    }
107
5
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_115require_decimalIlEEvT_jjjjPKc
Line
Count
Source
92
8
                     uint32_t maximum_scale, const char* description) {
93
8
    if (precision == 0 || precision > maximum_precision) {
94
2
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} precision {} is outside [1, {}]",
95
2
                        description, precision, maximum_precision);
96
2
    }
97
6
    if (scale > maximum_scale) {
98
1
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} scale {} exceeds {}", description, scale,
99
1
                        maximum_scale);
100
1
    }
101
5
    const uint32_t digits = decimal_digits(value);
102
5
    if (digits > precision) {
103
1
        throw Exception(ErrorCode::CORRUPTION,
104
1
                        "JSONB {} value has {} digits but declared precision is {}", description,
105
1
                        digits, precision);
106
1
    }
107
5
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_115require_decimalIN4wide7integerILm256EiEEEEvT_jjjjPKc
Line
Count
Source
92
9
                     uint32_t maximum_scale, const char* description) {
93
9
    if (precision == 0 || precision > maximum_precision) {
94
1
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} precision {} is outside [1, {}]",
95
1
                        description, precision, maximum_precision);
96
1
    }
97
8
    if (scale > maximum_scale) {
98
1
        throw Exception(ErrorCode::CORRUPTION, "JSONB {} scale {} exceeds {}", description, scale,
99
1
                        maximum_scale);
100
1
    }
101
7
    const uint32_t digits = decimal_digits(value);
102
7
    if (digits > precision) {
103
2
        throw Exception(ErrorCode::CORRUPTION,
104
2
                        "JSONB {} value has {} digits but declared precision is {}", description,
105
2
                        digits, precision);
106
2
    }
107
7
}
108
109
5
variant_json_detail::FormattedScalar format_decimal256(wide::Int256 value, uint32_t scale) {
110
5
    variant_json_detail::FormattedScalar result;
111
5
    std::array<char, 76> reversed {};
112
5
    size_t digits = 0;
113
5
    wide::Int256 remaining = value;
114
163
    do {
115
163
        int digit = static_cast<int>(remaining % 10);
116
163
        if (digit < 0) {
117
82
            digit = -digit;
118
82
        }
119
163
        reversed[digits++] = static_cast<char>('0' + digit);
120
163
        remaining /= 10;
121
163
    } while (remaining != 0);
122
123
248
    const auto append = [&](char byte) { result.bytes[result.size++] = byte; };
124
5
    if (value < 0) {
125
3
        append('-');
126
3
    }
127
5
    if (scale == 0) {
128
0
        while (digits != 0) {
129
0
            append(reversed[--digits]);
130
0
        }
131
0
        return result;
132
0
    }
133
5
    if (digits <= scale) {
134
2
        append('0');
135
2
        append('.');
136
77
        for (size_t zero = digits; zero < scale; ++zero) {
137
75
            append('0');
138
75
        }
139
3
    } else {
140
45
        while (digits > scale) {
141
42
            append(reversed[--digits]);
142
42
        }
143
3
        append('.');
144
3
    }
145
126
    while (digits != 0) {
146
121
        append(reversed[--digits]);
147
121
    }
148
5
    return result;
149
5
}
150
151
1.28k
void require_jsonb_depth(uint32_t depth, bool is_container) {
152
1.28k
    if (depth > MaxNestingLevel || (is_container && depth == MaxNestingLevel)) {
153
3
        throw Exception(ErrorCode::INVALID_ARGUMENT,
154
3
                        "JSONB traversal exceeds maximum container nesting {}", MaxNestingLevel);
155
3
    }
156
1.28k
}
157
158
999
void require_variant_depth(uint32_t base_depth, uint32_t relative_depth, bool is_container) {
159
999
    if (base_depth > VARIANT_MAX_NESTING_DEPTH ||
160
999
        relative_depth > VARIANT_MAX_NESTING_DEPTH - base_depth ||
161
999
        (is_container && base_depth + relative_depth == VARIANT_MAX_NESTING_DEPTH)) {
162
0
        throw Exception(ErrorCode::INVALID_ARGUMENT,
163
0
                        "JSONB traversal exceeds maximum Variant container nesting {}",
164
0
                        VARIANT_MAX_NESTING_DEPTH);
165
0
    }
166
999
}
167
168
template <typename Builder>
169
void collect_jsonb_value(BoundedJsonbCursor& cursor, Builder& builder, uint32_t relative_depth,
170
                         uint32_t base_depth);
171
172
template <typename Builder>
173
void collect_jsonb_object(BoundedJsonbCursor& cursor, Builder& builder, uint32_t relative_depth,
174
33
                          uint32_t base_depth) {
175
33
    require_jsonb_depth(relative_depth, true);
176
33
    require_variant_depth(base_depth, relative_depth, true);
177
33
    const auto payload_size = cursor.read<uint32_t>("object payload size");
178
33
    BoundedJsonbCursor payload = cursor.read_region(payload_size, "object payload");
179
33
    auto scope = builder.start_object();
180
51
    while (!payload.empty()) {
181
19
        const auto key_size = payload.read<uint8_t>("object key size");
182
19
        StringRef key;
183
19
        if (key_size == 0) {
184
2
            const auto key_id = payload.read<JsonbKeyValue::keyid_type>("object key id");
185
2
            if (key_id != JsonbKeyValue::sMaxKeyId) {
186
1
                throw Exception(ErrorCode::INVALID_ARGUMENT,
187
1
                                "Cannot resolve external JSONB object key id {} without a "
188
1
                                "dictionary",
189
1
                                key_id);
190
1
            }
191
17
        } else {
192
17
            key = payload.read_bytes(key_size, "object key");
193
17
        }
194
18
        scope.add_key(key);
195
18
        collect_jsonb_value(payload, builder, relative_depth + 1, base_depth);
196
18
    }
197
32
    scope.finish();
198
32
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_120collect_jsonb_objectINS_19VariantBlockBuilder3RowEEEvRNS0_18BoundedJsonbCursorERT_jj
Line
Count
Source
174
7
                          uint32_t base_depth) {
175
7
    require_jsonb_depth(relative_depth, true);
176
7
    require_variant_depth(base_depth, relative_depth, true);
177
7
    const auto payload_size = cursor.read<uint32_t>("object payload size");
178
7
    BoundedJsonbCursor payload = cursor.read_region(payload_size, "object payload");
179
7
    auto scope = builder.start_object();
180
16
    while (!payload.empty()) {
181
9
        const auto key_size = payload.read<uint8_t>("object key size");
182
9
        StringRef key;
183
9
        if (key_size == 0) {
184
0
            const auto key_id = payload.read<JsonbKeyValue::keyid_type>("object key id");
185
0
            if (key_id != JsonbKeyValue::sMaxKeyId) {
186
0
                throw Exception(ErrorCode::INVALID_ARGUMENT,
187
0
                                "Cannot resolve external JSONB object key id {} without a "
188
0
                                "dictionary",
189
0
                                key_id);
190
0
            }
191
9
        } else {
192
9
            key = payload.read_bytes(key_size, "object key");
193
9
        }
194
9
        scope.add_key(key);
195
9
        collect_jsonb_value(payload, builder, relative_depth + 1, base_depth);
196
9
    }
197
7
    scope.finish();
198
7
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_120collect_jsonb_objectINS_14VariantBuilderEEEvRNS0_18BoundedJsonbCursorERT_jj
Line
Count
Source
174
26
                          uint32_t base_depth) {
175
26
    require_jsonb_depth(relative_depth, true);
176
26
    require_variant_depth(base_depth, relative_depth, true);
177
26
    const auto payload_size = cursor.read<uint32_t>("object payload size");
178
26
    BoundedJsonbCursor payload = cursor.read_region(payload_size, "object payload");
179
26
    auto scope = builder.start_object();
180
35
    while (!payload.empty()) {
181
10
        const auto key_size = payload.read<uint8_t>("object key size");
182
10
        StringRef key;
183
10
        if (key_size == 0) {
184
2
            const auto key_id = payload.read<JsonbKeyValue::keyid_type>("object key id");
185
2
            if (key_id != JsonbKeyValue::sMaxKeyId) {
186
1
                throw Exception(ErrorCode::INVALID_ARGUMENT,
187
1
                                "Cannot resolve external JSONB object key id {} without a "
188
1
                                "dictionary",
189
1
                                key_id);
190
1
            }
191
8
        } else {
192
8
            key = payload.read_bytes(key_size, "object key");
193
8
        }
194
9
        scope.add_key(key);
195
9
        collect_jsonb_value(payload, builder, relative_depth + 1, base_depth);
196
9
    }
197
25
    scope.finish();
198
25
}
199
200
template <typename Builder>
201
void collect_jsonb_array(BoundedJsonbCursor& cursor, Builder& builder, uint32_t relative_depth,
202
314
                         uint32_t base_depth) {
203
314
    require_jsonb_depth(relative_depth, true);
204
314
    require_variant_depth(base_depth, relative_depth, true);
205
314
    const auto payload_size = cursor.read<uint32_t>("array payload size");
206
314
    BoundedJsonbCursor payload = cursor.read_region(payload_size, "array payload");
207
314
    auto scope = builder.start_array();
208
674
    while (!payload.empty()) {
209
360
        collect_jsonb_value(payload, builder, relative_depth + 1, base_depth);
210
360
    }
211
314
    scope.finish();
212
314
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_119collect_jsonb_arrayINS_19VariantBlockBuilder3RowEEEvRNS0_18BoundedJsonbCursorERT_jj
Line
Count
Source
202
104
                         uint32_t base_depth) {
203
104
    require_jsonb_depth(relative_depth, true);
204
104
    require_variant_depth(base_depth, relative_depth, true);
205
104
    const auto payload_size = cursor.read<uint32_t>("array payload size");
206
104
    BoundedJsonbCursor payload = cursor.read_region(payload_size, "array payload");
207
104
    auto scope = builder.start_array();
208
211
    while (!payload.empty()) {
209
107
        collect_jsonb_value(payload, builder, relative_depth + 1, base_depth);
210
107
    }
211
104
    scope.finish();
212
104
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_119collect_jsonb_arrayINS_14VariantBuilderEEEvRNS0_18BoundedJsonbCursorERT_jj
Line
Count
Source
202
210
                         uint32_t base_depth) {
203
210
    require_jsonb_depth(relative_depth, true);
204
210
    require_variant_depth(base_depth, relative_depth, true);
205
210
    const auto payload_size = cursor.read<uint32_t>("array payload size");
206
210
    BoundedJsonbCursor payload = cursor.read_region(payload_size, "array payload");
207
210
    auto scope = builder.start_array();
208
463
    while (!payload.empty()) {
209
253
        collect_jsonb_value(payload, builder, relative_depth + 1, base_depth);
210
253
    }
211
210
    scope.finish();
212
210
}
213
214
template <typename Native, typename Builder>
215
void collect_jsonb_decimal(BoundedJsonbCursor& cursor, Builder& builder, uint8_t width,
216
77
                           uint32_t maximum_precision, const char* description) {
217
77
    const auto precision = cursor.read<uint32_t>("decimal precision");
218
77
    const auto scale = cursor.read<uint32_t>("decimal scale");
219
77
    const auto value = cursor.read<Native>("decimal value");
220
77
    require_decimal(value, precision, scale, maximum_precision, 38, description);
221
77
    builder.add_decimal(static_cast<__int128>(value), static_cast<uint8_t>(scale), width);
222
77
}
Unexecuted instantiation: variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_121collect_jsonb_decimalIiNS_19VariantBlockBuilder3RowEEEvRNS0_18BoundedJsonbCursorERT0_hjPKc
Unexecuted instantiation: variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_121collect_jsonb_decimalIlNS_19VariantBlockBuilder3RowEEEvRNS0_18BoundedJsonbCursorERT0_hjPKc
Unexecuted instantiation: variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_121collect_jsonb_decimalInNS_19VariantBlockBuilder3RowEEEvRNS0_18BoundedJsonbCursorERT0_hjPKc
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_121collect_jsonb_decimalIiNS_14VariantBuilderEEEvRNS0_18BoundedJsonbCursorERT0_hjPKc
Line
Count
Source
216
20
                           uint32_t maximum_precision, const char* description) {
217
20
    const auto precision = cursor.read<uint32_t>("decimal precision");
218
20
    const auto scale = cursor.read<uint32_t>("decimal scale");
219
20
    const auto value = cursor.read<Native>("decimal value");
220
20
    require_decimal(value, precision, scale, maximum_precision, 38, description);
221
20
    builder.add_decimal(static_cast<__int128>(value), static_cast<uint8_t>(scale), width);
222
20
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_121collect_jsonb_decimalIlNS_14VariantBuilderEEEvRNS0_18BoundedJsonbCursorERT0_hjPKc
Line
Count
Source
216
24
                           uint32_t maximum_precision, const char* description) {
217
24
    const auto precision = cursor.read<uint32_t>("decimal precision");
218
24
    const auto scale = cursor.read<uint32_t>("decimal scale");
219
24
    const auto value = cursor.read<Native>("decimal value");
220
24
    require_decimal(value, precision, scale, maximum_precision, 38, description);
221
24
    builder.add_decimal(static_cast<__int128>(value), static_cast<uint8_t>(scale), width);
222
24
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_121collect_jsonb_decimalInNS_14VariantBuilderEEEvRNS0_18BoundedJsonbCursorERT0_hjPKc
Line
Count
Source
216
33
                           uint32_t maximum_precision, const char* description) {
217
33
    const auto precision = cursor.read<uint32_t>("decimal precision");
218
33
    const auto scale = cursor.read<uint32_t>("decimal scale");
219
33
    const auto value = cursor.read<Native>("decimal value");
220
33
    require_decimal(value, precision, scale, maximum_precision, 38, description);
221
33
    builder.add_decimal(static_cast<__int128>(value), static_cast<uint8_t>(scale), width);
222
33
}
223
224
template <typename Builder>
225
void collect_jsonb_value(BoundedJsonbCursor& cursor, Builder& builder, uint32_t relative_depth,
226
654
                         uint32_t base_depth) {
227
654
    require_jsonb_depth(relative_depth, false);
228
654
    require_variant_depth(base_depth, relative_depth, false);
229
654
    const auto type = static_cast<JsonbType>(cursor.read<uint8_t>("value type"));
230
654
    switch (type) {
231
15
    case JsonbType::T_Null:
232
15
        builder.add_null();
233
15
        return;
234
5
    case JsonbType::T_True:
235
5
        builder.add_bool(true);
236
5
        return;
237
2
    case JsonbType::T_False:
238
2
        builder.add_bool(false);
239
2
        return;
240
8
    case JsonbType::T_Int8:
241
8
        builder.add_int(cursor.read<int8_t>("int8 value"));
242
8
        return;
243
5
    case JsonbType::T_Int16:
244
5
        builder.add_int(cursor.read<int16_t>("int16 value"));
245
5
        return;
246
7
    case JsonbType::T_Int32:
247
7
        builder.add_int(cursor.read<int32_t>("int32 value"));
248
7
        return;
249
12
    case JsonbType::T_Int64:
250
12
        builder.add_int(cursor.read<int64_t>("int64 value"));
251
12
        return;
252
10
    case JsonbType::T_Double:
253
10
        builder.add_double(cursor.read<double>("double value"));
254
10
        return;
255
18
    case JsonbType::T_String: {
256
18
        const auto size = cursor.read<uint32_t>("string size");
257
18
        builder.add_string(cursor.read_bytes(size, "string payload"));
258
18
        return;
259
0
    }
260
11
    case JsonbType::T_Binary: {
261
11
        const auto size = cursor.read<uint32_t>("binary size");
262
11
        builder.add_binary(cursor.read_bytes(size, "binary payload"));
263
11
        return;
264
0
    }
265
33
    case JsonbType::T_Object:
266
33
        collect_jsonb_object(cursor, builder, relative_depth, base_depth);
267
33
        return;
268
314
    case JsonbType::T_Array:
269
314
        collect_jsonb_array(cursor, builder, relative_depth, base_depth);
270
314
        return;
271
25
    case JsonbType::T_Int128:
272
25
        builder.add_largeint(cursor.read<__int128>("int128 value"));
273
25
        return;
274
6
    case JsonbType::T_Float:
275
6
        builder.add_float(cursor.read<float>("float value"));
276
6
        return;
277
20
    case JsonbType::T_Decimal32:
278
20
        collect_jsonb_decimal<int32_t>(cursor, builder, 4, 9, "Decimal32");
279
20
        return;
280
24
    case JsonbType::T_Decimal64:
281
24
        collect_jsonb_decimal<int64_t>(cursor, builder, 8, 18, "Decimal64");
282
24
        return;
283
33
    case JsonbType::T_Decimal128:
284
33
        collect_jsonb_decimal<__int128>(cursor, builder, 16, 38, "Decimal128");
285
33
        return;
286
89
    case JsonbType::T_Decimal256: {
287
89
        const auto precision = cursor.read<uint32_t>("Decimal256 precision");
288
89
        const auto scale = cursor.read<uint32_t>("Decimal256 scale");
289
89
        const auto value = cursor.read<wide::Int256>("Decimal256 value");
290
89
        require_decimal(value, precision, scale, 76, 76, "Decimal256");
291
89
        const auto formatted = format_decimal256(value, scale);
292
89
        builder.add_string({formatted.bytes.data(), formatted.size});
293
89
        return;
294
0
    }
295
0
    case JsonbType::NUM_TYPES:
296
0
        break;
297
654
    }
298
2
    throw Exception(ErrorCode::CORRUPTION, "Unknown JSONB value type {}",
299
2
                    static_cast<uint8_t>(type));
300
654
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_119collect_jsonb_valueINS_19VariantBlockBuilder3RowEEEvRNS0_18BoundedJsonbCursorERT_jj
Line
Count
Source
226
130
                         uint32_t base_depth) {
227
130
    require_jsonb_depth(relative_depth, false);
228
130
    require_variant_depth(base_depth, relative_depth, false);
229
130
    const auto type = static_cast<JsonbType>(cursor.read<uint8_t>("value type"));
230
130
    switch (type) {
231
6
    case JsonbType::T_Null:
232
6
        builder.add_null();
233
6
        return;
234
2
    case JsonbType::T_True:
235
2
        builder.add_bool(true);
236
2
        return;
237
0
    case JsonbType::T_False:
238
0
        builder.add_bool(false);
239
0
        return;
240
5
    case JsonbType::T_Int8:
241
5
        builder.add_int(cursor.read<int8_t>("int8 value"));
242
5
        return;
243
1
    case JsonbType::T_Int16:
244
1
        builder.add_int(cursor.read<int16_t>("int16 value"));
245
1
        return;
246
1
    case JsonbType::T_Int32:
247
1
        builder.add_int(cursor.read<int32_t>("int32 value"));
248
1
        return;
249
1
    case JsonbType::T_Int64:
250
1
        builder.add_int(cursor.read<int64_t>("int64 value"));
251
1
        return;
252
0
    case JsonbType::T_Double:
253
0
        builder.add_double(cursor.read<double>("double value"));
254
0
        return;
255
2
    case JsonbType::T_String: {
256
2
        const auto size = cursor.read<uint32_t>("string size");
257
2
        builder.add_string(cursor.read_bytes(size, "string payload"));
258
2
        return;
259
0
    }
260
0
    case JsonbType::T_Binary: {
261
0
        const auto size = cursor.read<uint32_t>("binary size");
262
0
        builder.add_binary(cursor.read_bytes(size, "binary payload"));
263
0
        return;
264
0
    }
265
7
    case JsonbType::T_Object:
266
7
        collect_jsonb_object(cursor, builder, relative_depth, base_depth);
267
7
        return;
268
104
    case JsonbType::T_Array:
269
104
        collect_jsonb_array(cursor, builder, relative_depth, base_depth);
270
104
        return;
271
0
    case JsonbType::T_Int128:
272
0
        builder.add_largeint(cursor.read<__int128>("int128 value"));
273
0
        return;
274
0
    case JsonbType::T_Float:
275
0
        builder.add_float(cursor.read<float>("float value"));
276
0
        return;
277
0
    case JsonbType::T_Decimal32:
278
0
        collect_jsonb_decimal<int32_t>(cursor, builder, 4, 9, "Decimal32");
279
0
        return;
280
0
    case JsonbType::T_Decimal64:
281
0
        collect_jsonb_decimal<int64_t>(cursor, builder, 8, 18, "Decimal64");
282
0
        return;
283
0
    case JsonbType::T_Decimal128:
284
0
        collect_jsonb_decimal<__int128>(cursor, builder, 16, 38, "Decimal128");
285
0
        return;
286
0
    case JsonbType::T_Decimal256: {
287
0
        const auto precision = cursor.read<uint32_t>("Decimal256 precision");
288
0
        const auto scale = cursor.read<uint32_t>("Decimal256 scale");
289
0
        const auto value = cursor.read<wide::Int256>("Decimal256 value");
290
0
        require_decimal(value, precision, scale, 76, 76, "Decimal256");
291
0
        const auto formatted = format_decimal256(value, scale);
292
0
        builder.add_string({formatted.bytes.data(), formatted.size});
293
0
        return;
294
0
    }
295
0
    case JsonbType::NUM_TYPES:
296
0
        break;
297
130
    }
298
1
    throw Exception(ErrorCode::CORRUPTION, "Unknown JSONB value type {}",
299
1
                    static_cast<uint8_t>(type));
300
130
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_119collect_jsonb_valueINS_14VariantBuilderEEEvRNS0_18BoundedJsonbCursorERT_jj
Line
Count
Source
226
524
                         uint32_t base_depth) {
227
524
    require_jsonb_depth(relative_depth, false);
228
524
    require_variant_depth(base_depth, relative_depth, false);
229
524
    const auto type = static_cast<JsonbType>(cursor.read<uint8_t>("value type"));
230
524
    switch (type) {
231
9
    case JsonbType::T_Null:
232
9
        builder.add_null();
233
9
        return;
234
3
    case JsonbType::T_True:
235
3
        builder.add_bool(true);
236
3
        return;
237
2
    case JsonbType::T_False:
238
2
        builder.add_bool(false);
239
2
        return;
240
3
    case JsonbType::T_Int8:
241
3
        builder.add_int(cursor.read<int8_t>("int8 value"));
242
3
        return;
243
4
    case JsonbType::T_Int16:
244
4
        builder.add_int(cursor.read<int16_t>("int16 value"));
245
4
        return;
246
6
    case JsonbType::T_Int32:
247
6
        builder.add_int(cursor.read<int32_t>("int32 value"));
248
6
        return;
249
11
    case JsonbType::T_Int64:
250
11
        builder.add_int(cursor.read<int64_t>("int64 value"));
251
11
        return;
252
10
    case JsonbType::T_Double:
253
10
        builder.add_double(cursor.read<double>("double value"));
254
10
        return;
255
16
    case JsonbType::T_String: {
256
16
        const auto size = cursor.read<uint32_t>("string size");
257
16
        builder.add_string(cursor.read_bytes(size, "string payload"));
258
16
        return;
259
0
    }
260
11
    case JsonbType::T_Binary: {
261
11
        const auto size = cursor.read<uint32_t>("binary size");
262
11
        builder.add_binary(cursor.read_bytes(size, "binary payload"));
263
11
        return;
264
0
    }
265
26
    case JsonbType::T_Object:
266
26
        collect_jsonb_object(cursor, builder, relative_depth, base_depth);
267
26
        return;
268
210
    case JsonbType::T_Array:
269
210
        collect_jsonb_array(cursor, builder, relative_depth, base_depth);
270
210
        return;
271
25
    case JsonbType::T_Int128:
272
25
        builder.add_largeint(cursor.read<__int128>("int128 value"));
273
25
        return;
274
6
    case JsonbType::T_Float:
275
6
        builder.add_float(cursor.read<float>("float value"));
276
6
        return;
277
20
    case JsonbType::T_Decimal32:
278
20
        collect_jsonb_decimal<int32_t>(cursor, builder, 4, 9, "Decimal32");
279
20
        return;
280
24
    case JsonbType::T_Decimal64:
281
24
        collect_jsonb_decimal<int64_t>(cursor, builder, 8, 18, "Decimal64");
282
24
        return;
283
33
    case JsonbType::T_Decimal128:
284
33
        collect_jsonb_decimal<__int128>(cursor, builder, 16, 38, "Decimal128");
285
33
        return;
286
89
    case JsonbType::T_Decimal256: {
287
89
        const auto precision = cursor.read<uint32_t>("Decimal256 precision");
288
89
        const auto scale = cursor.read<uint32_t>("Decimal256 scale");
289
89
        const auto value = cursor.read<wide::Int256>("Decimal256 value");
290
89
        require_decimal(value, precision, scale, 76, 76, "Decimal256");
291
89
        const auto formatted = format_decimal256(value, scale);
292
89
        builder.add_string({formatted.bytes.data(), formatted.size});
293
89
        return;
294
0
    }
295
0
    case JsonbType::NUM_TYPES:
296
0
        break;
297
524
    }
298
1
    throw Exception(ErrorCode::CORRUPTION, "Unknown JSONB value type {}",
299
1
                    static_cast<uint8_t>(type));
300
524
}
301
302
template <typename Builder>
303
282
void collect_jsonb_document(StringRef document, Builder& builder, uint32_t initial_depth = 0) {
304
282
    if (document.data == nullptr && document.size != 0) {
305
1
        throw Exception(ErrorCode::INVALID_ARGUMENT,
306
1
                        "JSONB input has a null data pointer for {} bytes", document.size);
307
1
    }
308
281
    if (document.size == 0) {
309
2
        builder.add_null();
310
2
        return;
311
2
    }
312
313
279
    BoundedJsonbCursor cursor(document.data, document.size);
314
279
    const auto version = cursor.read<uint8_t>("document version");
315
279
    if (version != JSONB_VER) {
316
2
        throw Exception(ErrorCode::CORRUPTION, "Unsupported JSONB version {}, expected {}", version,
317
2
                        JSONB_VER);
318
2
    }
319
277
    collect_jsonb_value(cursor, builder, 0, initial_depth);
320
277
    if (!cursor.empty()) {
321
1
        throw Exception(ErrorCode::CORRUPTION,
322
1
                        "JSONB document has {} trailing bytes after its root value",
323
1
                        cursor.remaining());
324
1
    }
325
277
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_122collect_jsonb_documentINS_19VariantBlockBuilder3RowEEEvNS_9StringRefERT_j
Line
Count
Source
303
16
void collect_jsonb_document(StringRef document, Builder& builder, uint32_t initial_depth = 0) {
304
16
    if (document.data == nullptr && document.size != 0) {
305
0
        throw Exception(ErrorCode::INVALID_ARGUMENT,
306
0
                        "JSONB input has a null data pointer for {} bytes", document.size);
307
0
    }
308
16
    if (document.size == 0) {
309
1
        builder.add_null();
310
1
        return;
311
1
    }
312
313
15
    BoundedJsonbCursor cursor(document.data, document.size);
314
15
    const auto version = cursor.read<uint8_t>("document version");
315
15
    if (version != JSONB_VER) {
316
1
        throw Exception(ErrorCode::CORRUPTION, "Unsupported JSONB version {}, expected {}", version,
317
1
                        JSONB_VER);
318
1
    }
319
14
    collect_jsonb_value(cursor, builder, 0, initial_depth);
320
14
    if (!cursor.empty()) {
321
0
        throw Exception(ErrorCode::CORRUPTION,
322
0
                        "JSONB document has {} trailing bytes after its root value",
323
0
                        cursor.remaining());
324
0
    }
325
14
}
variant_jsonb.cpp:_ZN5doris12_GLOBAL__N_122collect_jsonb_documentINS_14VariantBuilderEEEvNS_9StringRefERT_j
Line
Count
Source
303
266
void collect_jsonb_document(StringRef document, Builder& builder, uint32_t initial_depth = 0) {
304
266
    if (document.data == nullptr && document.size != 0) {
305
1
        throw Exception(ErrorCode::INVALID_ARGUMENT,
306
1
                        "JSONB input has a null data pointer for {} bytes", document.size);
307
1
    }
308
265
    if (document.size == 0) {
309
1
        builder.add_null();
310
1
        return;
311
1
    }
312
313
264
    BoundedJsonbCursor cursor(document.data, document.size);
314
264
    const auto version = cursor.read<uint8_t>("document version");
315
264
    if (version != JSONB_VER) {
316
1
        throw Exception(ErrorCode::CORRUPTION, "Unsupported JSONB version {}, expected {}", version,
317
1
                        JSONB_VER);
318
1
    }
319
263
    collect_jsonb_value(cursor, builder, 0, initial_depth);
320
263
    if (!cursor.empty()) {
321
1
        throw Exception(ErrorCode::CORRUPTION,
322
1
                        "JSONB document has {} trailing bytes after its root value",
323
1
                        cursor.remaining());
324
1
    }
325
263
}
326
327
439
void require_jsonb_write(bool written, const char* operation) {
328
439
    if (!written) {
329
0
        throw Exception(ErrorCode::INVALID_ARGUMENT, "JSONB writer rejected {}", operation);
330
0
    }
331
439
}
332
333
18
void write_jsonb_string(JsonbWriter& writer, StringRef value, const char* description) {
334
18
    variant_json_detail::require_valid_json_utf8(value, description);
335
18
    require_jsonb_write(writer.writeStartString(), "string start");
336
18
    require_jsonb_write(writer.writeString(value.data, value.size), "string payload");
337
18
    require_jsonb_write(writer.writeEndString(), "string end");
338
18
}
339
340
11
void write_jsonb_string(JsonbWriter& writer, const variant_json_detail::FormattedScalar& value) {
341
11
    write_jsonb_string(writer, {value.bytes.data(), value.size}, "formatted string");
342
11
}
343
344
2
void write_jsonb_binary(JsonbWriter& writer, StringRef value) {
345
2
    require_jsonb_write(writer.writeStartBinary(), "binary start");
346
2
    require_jsonb_write(writer.writeBinary(value.data, value.size), "binary payload");
347
2
    require_jsonb_write(writer.writeEndBinary(), "binary end");
348
2
}
349
350
class VariantToJsonbConverter {
351
public:
352
    VariantToJsonbConverter(JsonbWriter& writer, const VariantJsonFormatOptions& options)
353
27
            : _writer(writer), _options(options) {}
354
355
285
    void write(VariantValueRef value, uint32_t depth) {
356
285
        const VariantBasicType type = value.basic_type();
357
285
        const bool is_container =
358
285
                type == VariantBasicType::OBJECT || type == VariantBasicType::ARRAY;
359
285
        require_jsonb_depth(depth, is_container);
360
285
        switch (type) {
361
6
        case VariantBasicType::SHORT_STRING:
362
6
            write_jsonb_string(_writer, value.get_string(), "Variant string");
363
6
            return;
364
63
        case VariantBasicType::PRIMITIVE:
365
63
            write_primitive(value);
366
63
            return;
367
8
        case VariantBasicType::OBJECT:
368
8
            write_object(value, depth);
369
8
            return;
370
207
        case VariantBasicType::ARRAY:
371
207
            write_array(value, depth);
372
207
            return;
373
285
        }
374
285
    }
375
376
private:
377
12
    void write_decimal(VariantDecimal decimal) {
378
12
        uint32_t precision = 38;
379
12
        if (decimal.width == 4) {
380
4
            precision = 9;
381
8
        } else if (decimal.width == 8) {
382
3
            precision = 18;
383
3
        }
384
12
        require_decimal(decimal.unscaled, precision, decimal.scale, precision, 38,
385
12
                        "Variant decimal");
386
12
        if (decimal.width == 4) {
387
3
            require_jsonb_write(
388
3
                    _writer.writeDecimal(Decimal32 {static_cast<int32_t>(decimal.unscaled)},
389
3
                                         precision, decimal.scale),
390
3
                    "Decimal32 value");
391
9
        } else if (decimal.width == 8) {
392
3
            require_jsonb_write(
393
3
                    _writer.writeDecimal(Decimal64 {static_cast<int64_t>(decimal.unscaled)},
394
3
                                         precision, decimal.scale),
395
3
                    "Decimal64 value");
396
6
        } else {
397
6
            require_jsonb_write(
398
6
                    _writer.writeDecimal(Decimal128V3 {decimal.unscaled}, precision, decimal.scale),
399
6
                    "Decimal128 value");
400
6
        }
401
12
    }
402
403
63
    void write_primitive(VariantValueRef value) {
404
63
        switch (value.primitive_id()) {
405
11
        case VariantPrimitiveId::NULL_VALUE:
406
11
            require_jsonb_write(_writer.writeNull(), "null value");
407
11
            return;
408
4
        case VariantPrimitiveId::TRUE_VALUE:
409
4
            require_jsonb_write(_writer.writeBool(true), "true value");
410
4
            return;
411
3
        case VariantPrimitiveId::FALSE_VALUE:
412
3
            require_jsonb_write(_writer.writeBool(false), "false value");
413
3
            return;
414
8
        case VariantPrimitiveId::INT8:
415
8
            require_jsonb_write(_writer.writeInt8(static_cast<int8_t>(value.get_int())),
416
8
                                "int8 value");
417
8
            return;
418
2
        case VariantPrimitiveId::INT16:
419
2
            require_jsonb_write(_writer.writeInt16(static_cast<int16_t>(value.get_int())),
420
2
                                "int16 value");
421
2
            return;
422
2
        case VariantPrimitiveId::INT32:
423
2
            require_jsonb_write(_writer.writeInt32(static_cast<int32_t>(value.get_int())),
424
2
                                "int32 value");
425
2
            return;
426
2
        case VariantPrimitiveId::INT64:
427
2
            require_jsonb_write(_writer.writeInt64(value.get_int()), "int64 value");
428
2
            return;
429
2
        case VariantPrimitiveId::DOUBLE:
430
2
            require_jsonb_write(_writer.writeDouble(value.get_double()), "double value");
431
2
            return;
432
4
        case VariantPrimitiveId::DECIMAL4:
433
7
        case VariantPrimitiveId::DECIMAL8:
434
12
        case VariantPrimitiveId::DECIMAL16:
435
12
            write_decimal(value.get_decimal());
436
12
            return;
437
1
        case VariantPrimitiveId::DATE:
438
1
            write_jsonb_string(_writer, variant_json_detail::format_json_date(value.get_date()));
439
1
            return;
440
2
        case VariantPrimitiveId::TIMESTAMP_MICROS:
441
2
            write_jsonb_string(_writer,
442
2
                               variant_json_detail::format_json_timestamp(
443
2
                                       value.get_timestamp_micros(), 6, true, _options.timezone));
444
2
            return;
445
2
        case VariantPrimitiveId::TIMESTAMP_NTZ_MICROS:
446
2
            write_jsonb_string(_writer,
447
2
                               variant_json_detail::format_json_timestamp(
448
2
                                       value.get_timestamp_ntz_micros(), 6, false, nullptr));
449
2
            return;
450
2
        case VariantPrimitiveId::FLOAT:
451
2
            require_jsonb_write(_writer.writeFloat(value.get_float()), "float value");
452
2
            return;
453
2
        case VariantPrimitiveId::BINARY:
454
2
            write_jsonb_binary(_writer, value.get_binary());
455
2
            return;
456
1
        case VariantPrimitiveId::STRING:
457
1
            write_jsonb_string(_writer, value.get_string(), "Variant string");
458
1
            return;
459
2
        case VariantPrimitiveId::TIME_NTZ_MICROS:
460
2
            write_jsonb_string(_writer, variant_json_detail::format_json_time_micros(
461
2
                                                value.get_time_ntz_micros()));
462
2
            return;
463
2
        case VariantPrimitiveId::TIMESTAMP_NANOS:
464
2
            write_jsonb_string(_writer,
465
2
                               variant_json_detail::format_json_timestamp(
466
2
                                       value.get_timestamp_nanos(), 9, true, _options.timezone));
467
2
            return;
468
2
        case VariantPrimitiveId::TIMESTAMP_NTZ_NANOS:
469
2
            write_jsonb_string(_writer,
470
2
                               variant_json_detail::format_json_timestamp(
471
2
                                       value.get_timestamp_ntz_nanos(), 9, false, nullptr));
472
2
            return;
473
1
        case VariantPrimitiveId::UUID:
474
1
            write_jsonb_string(_writer, variant_json_detail::format_json_uuid(value.get_uuid()));
475
1
            return;
476
63
        }
477
0
        throw Exception(ErrorCode::CORRUPTION, "Unknown Variant primitive id");
478
63
    }
479
480
8
    void write_object(VariantValueRef value, uint32_t depth) {
481
8
        require_jsonb_write(_writer.writeStartObject(), "object start");
482
8
        const uint32_t count = value.num_elements();
483
8
        StringRef previous_key;
484
16
        for (uint32_t index = 0; index < count; ++index) {
485
11
            uint32_t field_id = 0;
486
11
            const VariantValueRef child = value.object_value_at(index, &field_id);
487
11
            const StringRef key = value.metadata.key_at(field_id);
488
11
            variant_json_detail::require_valid_json_utf8(key, "Variant object key");
489
11
            if (key.size > std::numeric_limits<uint8_t>::max()) {
490
1
                throw Exception(ErrorCode::INVALID_ARGUMENT,
491
1
                                "Variant object key length {} exceeds JSONB maximum {}", key.size,
492
1
                                std::numeric_limits<uint8_t>::max());
493
1
            }
494
10
            if (index != 0 && previous_key.compare(key) >= 0) {
495
2
                throw Exception(ErrorCode::CORRUPTION,
496
2
                                "Variant object keys are not strictly byte-sorted at field {}",
497
2
                                index);
498
2
            }
499
8
            require_jsonb_write(_writer.writeKey(key.data, static_cast<uint8_t>(key.size)),
500
8
                                "object key");
501
8
            write(child, depth + 1);
502
8
            previous_key = key;
503
8
        }
504
5
        require_jsonb_write(_writer.writeEndObject(), "object end");
505
5
    }
506
507
207
    void write_array(VariantValueRef value, uint32_t depth) {
508
207
        require_jsonb_write(_writer.writeStartArray(), "array start");
509
207
        const uint32_t count = value.num_elements();
510
457
        for (uint32_t index = 0; index < count; ++index) {
511
250
            write(value.array_at(index), depth + 1);
512
250
        }
513
207
        require_jsonb_write(_writer.writeEndArray(), "array end");
514
207
    }
515
516
    JsonbWriter& _writer;
517
    const VariantJsonFormatOptions& _options;
518
};
519
520
} // namespace
521
522
struct JsonbToVariantEncoder::Impl {
523
    enum class State : uint8_t { COLLECTING, FINISHED, FAILED };
524
525
16
    explicit Impl(VariantBlockBuilder::ReserveHint hint) : builder(hint) {}
526
527
35
    void require_collecting() const {
528
35
        if (state == State::FINISHED) {
529
2
            throw Exception(ErrorCode::INVALID_ARGUMENT,
530
2
                            "Variant JSONB encoder is already finished");
531
2
        }
532
33
        if (state == State::FAILED) {
533
3
            throw Exception(ErrorCode::INVALID_ARGUMENT,
534
3
                            "Variant JSONB encoder is in a terminal failed state");
535
3
        }
536
33
    }
537
538
    VariantBlockBuilder builder;
539
    State state = State::COLLECTING;
540
};
541
542
JsonbToVariantEncoder::JsonbToVariantEncoder()
543
11
        : JsonbToVariantEncoder(VariantBlockBuilder::ReserveHint {}) {}
544
JsonbToVariantEncoder::JsonbToVariantEncoder(VariantBlockBuilder::ReserveHint hint)
545
16
        : _impl(std::make_unique<Impl>(hint)) {}
546
16
JsonbToVariantEncoder::~JsonbToVariantEncoder() = default;
547
0
JsonbToVariantEncoder::JsonbToVariantEncoder(JsonbToVariantEncoder&&) noexcept = default;
548
0
JsonbToVariantEncoder& JsonbToVariantEncoder::operator=(JsonbToVariantEncoder&&) noexcept = default;
549
550
2
void JsonbToVariantEncoder::add_null() {
551
2
    _impl->require_collecting();
552
2
    try {
553
2
        auto row = _impl->builder.begin_row();
554
2
        row.add_null();
555
2
        row.finish();
556
2
    } catch (...) {
557
0
        _impl->state = Impl::State::FAILED;
558
0
        throw;
559
0
    }
560
2
}
561
562
18
void JsonbToVariantEncoder::add_jsonb(StringRef document) {
563
18
    _impl->require_collecting();
564
18
    try {
565
18
        auto row = _impl->builder.begin_row();
566
18
        collect_jsonb_document(document, row);
567
18
        row.finish();
568
18
    } catch (...) {
569
4
        _impl->state = Impl::State::FAILED;
570
4
        throw;
571
4
    }
572
18
}
573
574
15
VariantEncodedBlock JsonbToVariantEncoder::finish_block() {
575
15
    _impl->require_collecting();
576
15
    try {
577
15
        VariantEncodedBlock block = _impl->builder.finish_block();
578
15
        _impl->state = Impl::State::FINISHED;
579
15
        return block;
580
15
    } catch (...) {
581
0
        _impl->state = Impl::State::FAILED;
582
0
        throw;
583
0
    }
584
15
}
585
586
266
void jsonb_to_variant(StringRef document, VariantBuilder& builder) {
587
266
    try {
588
266
        collect_jsonb_document(document, builder);
589
266
    } catch (...) {
590
250
        builder.abort();
591
250
        throw;
592
250
    }
593
266
}
594
595
0
void jsonb_to_variant(StringRef document, VariantBlockBuilder::Row& row, uint32_t initial_depth) {
596
0
    try {
597
0
        collect_jsonb_document(document, row, initial_depth);
598
0
    } catch (...) {
599
0
        row.abort();
600
0
        throw;
601
0
    }
602
0
}
603
604
void variant_to_jsonb(VariantValueRef value, JsonbWriter& writer,
605
30
                      const VariantJsonFormatOptions& options) {
606
30
    writer.reset();
607
30
    try {
608
30
        if (value.metadata.version() != VARIANT_ENCODING_VERSION) {
609
0
            throw Exception(ErrorCode::CORRUPTION, "Unsupported Variant metadata version {}",
610
0
                            value.metadata.version());
611
0
        }
612
30
        static_cast<void>(value.metadata.dict_size());
613
30
        variant_json_detail::require_exact_json_value(value);
614
30
        VariantToJsonbConverter(writer, options).write(value, 0);
615
30
    } catch (...) {
616
10
        writer.reset();
617
10
        throw;
618
10
    }
619
30
}
620
621
} // namespace doris