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 |