be/src/format_v2/json/json_reader.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 "format_v2/json/json_reader.h" |
19 | | |
20 | | #include <rapidjson/document.h> |
21 | | |
22 | | #include <algorithm> |
23 | | #include <cstring> |
24 | | #include <limits> |
25 | | #include <map> |
26 | | #include <string_view> |
27 | | #include <utility> |
28 | | |
29 | | #include "common/cast_set.h" |
30 | | #include "core/assert_cast.h" |
31 | | #include "core/block/block.h" |
32 | | #include "core/column/column_array.h" |
33 | | #include "core/column/column_map.h" |
34 | | #include "core/column/column_nullable.h" |
35 | | #include "core/column/column_string.h" |
36 | | #include "core/column/column_struct.h" |
37 | | #include "core/data_type/data_type_array.h" |
38 | | #include "core/data_type/data_type_map.h" |
39 | | #include "core/data_type/data_type_nullable.h" |
40 | | #include "core/data_type/data_type_string.h" |
41 | | #include "core/data_type/data_type_struct.h" |
42 | | #include "format/file_reader/new_plain_text_line_reader.h" |
43 | | #include "format_v2/column_mapper.h" |
44 | | #include "format_v2/materialized_reader_util.h" |
45 | | #include "io/file_factory.h" |
46 | | #include "io/fs/file_reader.h" |
47 | | #include "io/fs/stream_load_pipe.h" |
48 | | #include "io/fs/tracing_file_reader.h" |
49 | | #include "runtime/descriptors.h" |
50 | | #include "runtime/runtime_state.h" |
51 | | #include "util/decompressor.h" |
52 | | #include "util/slice.h" |
53 | | |
54 | | namespace doris::format::json { |
55 | | namespace { |
56 | | |
57 | 36 | DataTypePtr json_file_type_from_slot_type(const DataTypePtr& type) { |
58 | 36 | if (type == nullptr) { |
59 | 0 | return nullptr; |
60 | 0 | } |
61 | | |
62 | | // Text-like file readers expose CHAR/VARCHAR as STRING and let the table column mapper cast to |
63 | | // the destination slot type. JSON follows the same file-schema convention so that v2 mapping |
64 | | // behaves consistently across text formats. |
65 | 36 | const bool is_nullable = type->is_nullable(); |
66 | 36 | const auto nested_type = remove_nullable(type); |
67 | 36 | DataTypePtr file_type; |
68 | 36 | switch (nested_type->get_primitive_type()) { |
69 | 1 | case TYPE_CHAR: |
70 | 4 | case TYPE_VARCHAR: |
71 | 4 | file_type = std::make_shared<DataTypeString>(); |
72 | 4 | break; |
73 | 2 | case TYPE_ARRAY: { |
74 | 2 | const auto* array_type = assert_cast<const DataTypeArray*>(nested_type.get()); |
75 | 2 | file_type = std::make_shared<DataTypeArray>( |
76 | 2 | json_file_type_from_slot_type(array_type->get_nested_type())); |
77 | 2 | break; |
78 | 1 | } |
79 | 1 | case TYPE_MAP: { |
80 | 1 | const auto* map_type = assert_cast<const DataTypeMap*>(nested_type.get()); |
81 | 1 | file_type = std::make_shared<DataTypeMap>( |
82 | 1 | json_file_type_from_slot_type(map_type->get_key_type()), |
83 | 1 | json_file_type_from_slot_type(map_type->get_value_type())); |
84 | 1 | break; |
85 | 1 | } |
86 | 1 | case TYPE_STRUCT: { |
87 | 1 | const auto* struct_type = assert_cast<const DataTypeStruct*>(nested_type.get()); |
88 | 1 | DataTypes file_children; |
89 | 1 | file_children.reserve(struct_type->get_elements().size()); |
90 | 2 | for (const auto& child_type : struct_type->get_elements()) { |
91 | 2 | file_children.push_back(json_file_type_from_slot_type(child_type)); |
92 | 2 | } |
93 | 1 | file_type = |
94 | 1 | std::make_shared<DataTypeStruct>(file_children, struct_type->get_element_names()); |
95 | 1 | break; |
96 | 1 | } |
97 | 28 | default: |
98 | 28 | file_type = nested_type; |
99 | 28 | break; |
100 | 36 | } |
101 | | |
102 | 36 | return is_nullable ? make_nullable(file_type) : file_type; |
103 | 36 | } |
104 | | |
105 | | ColumnDefinition synthetic_file_child(const std::string& name, DataTypePtr type, int32_t local_id); |
106 | | |
107 | 36 | std::vector<ColumnDefinition> synthesize_file_children_from_type(const DataTypePtr& type) { |
108 | 36 | std::vector<ColumnDefinition> children; |
109 | 36 | if (type == nullptr) { |
110 | 0 | return children; |
111 | 0 | } |
112 | 36 | const auto nested_type = remove_nullable(type); |
113 | 36 | switch (nested_type->get_primitive_type()) { |
114 | 2 | case TYPE_ARRAY: { |
115 | 2 | const auto* array_type = assert_cast<const DataTypeArray*>(nested_type.get()); |
116 | 2 | children.push_back(synthetic_file_child("element", array_type->get_nested_type(), 0)); |
117 | 2 | break; |
118 | 0 | } |
119 | 1 | case TYPE_MAP: { |
120 | 1 | const auto* map_type = assert_cast<const DataTypeMap*>(nested_type.get()); |
121 | 1 | children.push_back(synthetic_file_child("key", map_type->get_key_type(), 0)); |
122 | 1 | children.push_back(synthetic_file_child("value", map_type->get_value_type(), 1)); |
123 | 1 | break; |
124 | 0 | } |
125 | 1 | case TYPE_STRUCT: { |
126 | 1 | const auto* struct_type = assert_cast<const DataTypeStruct*>(nested_type.get()); |
127 | 1 | children.reserve(struct_type->get_elements().size()); |
128 | 3 | for (size_t idx = 0; idx < struct_type->get_elements().size(); ++idx) { |
129 | 2 | children.push_back(synthetic_file_child(struct_type->get_element_name(idx), |
130 | 2 | struct_type->get_element(idx), |
131 | 2 | cast_set<int32_t>(idx))); |
132 | 2 | } |
133 | 1 | break; |
134 | 0 | } |
135 | 32 | default: |
136 | 32 | break; |
137 | 36 | } |
138 | 36 | return children; |
139 | 36 | } |
140 | | |
141 | 6 | ColumnDefinition synthetic_file_child(const std::string& name, DataTypePtr type, int32_t local_id) { |
142 | 6 | ColumnDefinition child; |
143 | 6 | child.identifier = Field::create_field<TYPE_STRING>(name); |
144 | 6 | child.local_id = local_id; |
145 | 6 | child.name = name; |
146 | 6 | child.type = std::move(type); |
147 | 6 | child.children = synthesize_file_children_from_type(child.type); |
148 | 6 | return child; |
149 | 6 | } |
150 | | |
151 | 0 | std::string lower_key(std::string_view key) { |
152 | 0 | std::string lowered(key.data(), key.size()); |
153 | 0 | std::transform(lowered.begin(), lowered.end(), lowered.begin(), ::tolower); |
154 | 0 | return lowered; |
155 | 0 | } |
156 | | |
157 | | } // namespace |
158 | | |
159 | | JsonReader::JsonReader(std::shared_ptr<io::FileSystemProperties>& system_properties, |
160 | | std::unique_ptr<io::FileDescription>& file_description, |
161 | | std::shared_ptr<io::IOContext> io_ctx, RuntimeProfile* profile, |
162 | | const TFileScanRangeParams* scan_params, const TFileRangeDesc& range, |
163 | | const std::vector<SlotDescriptor*>& file_slot_descs, |
164 | | TFileCompressType::type range_compress_type, |
165 | | std::optional<TUniqueId> stream_load_id) |
166 | 14 | : FileReader(system_properties, file_description, std::move(io_ctx), profile), |
167 | 14 | _scan_params(scan_params), |
168 | 14 | _range(range), |
169 | 14 | _source_file_slot_descs(file_slot_descs), |
170 | 14 | _range_compress_type(range_compress_type), |
171 | 14 | _stream_load_id(std::move(stream_load_id)) {} |
172 | | |
173 | 14 | JsonReader::~JsonReader() { |
174 | 14 | static_cast<void>(close()); |
175 | 14 | } |
176 | | |
177 | 14 | Status JsonReader::init(RuntimeState* state) { |
178 | 14 | _runtime_state = state; |
179 | 14 | if (_scan_params == nullptr) { |
180 | 0 | return Status::InvalidArgument("JSON v2 reader requires scan params"); |
181 | 0 | } |
182 | 14 | if (_file_description == nullptr) { |
183 | 0 | return Status::InvalidArgument("JSON v2 reader requires file description"); |
184 | 0 | } |
185 | 14 | if (_runtime_state == nullptr) { |
186 | 0 | return Status::InvalidArgument("JSON v2 reader requires runtime state"); |
187 | 0 | } |
188 | 14 | if (!_scan_params->__isset.file_attributes) { |
189 | 0 | return Status::InvalidArgument("JSON v2 reader requires file attributes"); |
190 | 0 | } |
191 | | |
192 | 14 | const auto& attributes = _scan_params->file_attributes; |
193 | 14 | if (attributes.__isset.text_params && attributes.text_params.__isset.line_delimiter) { |
194 | 14 | _line_delimiter = attributes.text_params.line_delimiter; |
195 | 14 | } else { |
196 | 0 | _line_delimiter = "\n"; |
197 | 0 | } |
198 | 14 | _line_delimiter_length = _line_delimiter.size(); |
199 | 14 | _jsonpaths = attributes.__isset.jsonpaths ? attributes.jsonpaths : ""; |
200 | 14 | _json_root = attributes.__isset.json_root ? attributes.json_root : ""; |
201 | 14 | _read_json_by_line = attributes.__isset.read_json_by_line && attributes.read_json_by_line; |
202 | 14 | _strip_outer_array = attributes.__isset.strip_outer_array && attributes.strip_outer_array; |
203 | 14 | _num_as_string = attributes.__isset.num_as_string && attributes.num_as_string; |
204 | 14 | _fuzzy_parse = attributes.__isset.fuzzy_parse && attributes.fuzzy_parse; |
205 | 14 | _openx_json_ignore_malformed = attributes.__isset.openx_json_ignore_malformed && |
206 | 14 | attributes.openx_json_ignore_malformed; |
207 | 14 | _is_hive_table = _range.table_format_params.table_format_type == "hive"; |
208 | 14 | _file_compress_type = _range_compress_type != TFileCompressType::UNKNOWN |
209 | 14 | ? _range_compress_type |
210 | 14 | : _scan_params->compress_type; |
211 | | |
212 | 14 | _source_serdes = create_data_type_serdes(_source_file_slot_descs); |
213 | 14 | _file_schema.clear(); |
214 | 14 | _file_schema.reserve(_source_file_slot_descs.size()); |
215 | | // JSON has no physical footer schema. The FE file slots are therefore the authoritative schema |
216 | | // for both field names and source local ids. |
217 | 44 | for (size_t idx = 0; idx < _source_file_slot_descs.size(); ++idx) { |
218 | 30 | const auto* slot = _source_file_slot_descs[idx]; |
219 | 30 | DORIS_CHECK(slot != nullptr); |
220 | 30 | ColumnDefinition field; |
221 | 30 | field.identifier = Field::create_field<TYPE_STRING>(slot->col_name()); |
222 | 30 | field.local_id = cast_set<int32_t>(idx); |
223 | 30 | field.name = slot->col_name(); |
224 | 30 | field.type = json_file_type_from_slot_type(slot->get_data_type_ptr()); |
225 | 30 | field.children = synthesize_file_children_from_type(field.type); |
226 | 30 | _file_schema.push_back(std::move(field)); |
227 | 30 | } |
228 | 14 | _eof = false; |
229 | 14 | return Status::OK(); |
230 | 14 | } |
231 | | |
232 | 14 | Status JsonReader::get_schema(std::vector<ColumnDefinition>* file_schema) const { |
233 | 14 | if (file_schema == nullptr) { |
234 | 0 | return Status::InvalidArgument("JSON v2 file_schema is null"); |
235 | 0 | } |
236 | 14 | *file_schema = _file_schema; |
237 | 14 | return Status::OK(); |
238 | 14 | } |
239 | | |
240 | | std::unique_ptr<TableColumnMapper> JsonReader::create_column_mapper( |
241 | 0 | TableColumnMapperOptions options) const { |
242 | 0 | return std::make_unique<MaterializedColumnMapper>(std::move(options)); |
243 | 0 | } |
244 | | |
245 | 15 | Status JsonReader::open(std::shared_ptr<FileScanRequest> request) { |
246 | 15 | RETURN_IF_ERROR(FileReader::open(std::move(request))); |
247 | 15 | DORIS_CHECK(_request != nullptr); |
248 | 15 | RETURN_IF_ERROR(_build_requested_columns(*_request, &_requested_columns)); |
249 | 12 | _slot_name_to_index.clear(); |
250 | 12 | _slot_name_to_index.reserve(_requested_columns.size()); |
251 | 36 | for (size_t idx = 0; idx < _requested_columns.size(); ++idx) { |
252 | 24 | auto name = _requested_columns[idx].slot_desc->col_name(); |
253 | 24 | _slot_name_to_index.emplace(_is_hive_table ? lower_key(name) : name, idx); |
254 | 24 | } |
255 | 12 | _previous_positions.clear(); |
256 | 12 | _reader_range = _json_range(); |
257 | 12 | RETURN_IF_ERROR(_open_file_reader()); |
258 | 12 | RETURN_IF_ERROR(_create_decompressor()); |
259 | 12 | if (_read_json_by_line) { |
260 | 10 | RETURN_IF_ERROR(_create_line_reader()); |
261 | 10 | } |
262 | 12 | RETURN_IF_ERROR(_parse_jsonpath_and_json_root()); |
263 | 12 | _json_parser = std::make_unique<simdjson::ondemand::parser>(); |
264 | 12 | _padding_buffer.resize(_padded_size); |
265 | 12 | _reader_eof = false; |
266 | 12 | _single_document_read = false; |
267 | 12 | _eof = false; |
268 | 12 | return Status::OK(); |
269 | 12 | } |
270 | | |
271 | 14 | Status JsonReader::get_block(Block* file_block, size_t* rows, bool* eof) { |
272 | 14 | DORIS_CHECK(file_block != nullptr); |
273 | 14 | DORIS_CHECK(rows != nullptr); |
274 | 14 | DORIS_CHECK(eof != nullptr); |
275 | 14 | if (_json_parser == nullptr || _physical_file_reader == nullptr) { |
276 | 1 | return Status::InternalError("JSON v2 reader is not open"); |
277 | 1 | } |
278 | | |
279 | 13 | const auto batch_size = _runtime_state->batch_size(); |
280 | 13 | const auto max_block_bytes = _runtime_state->preferred_block_size_bytes(); |
281 | 13 | *rows = 0; |
282 | 13 | *eof = false; |
283 | | |
284 | 30 | while (file_block->rows() < batch_size && !_reader_eof && |
285 | 30 | file_block->bytes() < max_block_bytes) { |
286 | 29 | if (_read_json_by_line && _skip_first_line) { |
287 | 0 | size_t skipped_size = 0; |
288 | 0 | const uint8_t* skipped_line = nullptr; |
289 | 0 | RETURN_IF_ERROR(_line_reader->read_line(&skipped_line, &skipped_size, &_reader_eof, |
290 | 0 | _io_ctx.get())); |
291 | 0 | _skip_first_line = false; |
292 | 0 | continue; |
293 | 0 | } |
294 | | |
295 | 29 | const size_t original_rows = file_block->rows(); |
296 | 29 | size_t size = 0; |
297 | 29 | bool is_empty_row = false; |
298 | 29 | Status st = Status::OK(); |
299 | 29 | try { |
300 | 29 | st = _parse_next_json(&size, &_reader_eof); |
301 | 29 | if (st.ok() && !_reader_eof) { |
302 | 19 | if (size == 0) { |
303 | 1 | is_empty_row = true; |
304 | 18 | } else { |
305 | 18 | st = _extract_json_value(size, &_reader_eof, &is_empty_row); |
306 | 18 | } |
307 | 19 | } |
308 | 29 | if (st.ok() && !_reader_eof && !is_empty_row) { |
309 | 16 | st = _append_rows_from_current_value(file_block, &is_empty_row, &_reader_eof); |
310 | 16 | } |
311 | 29 | } catch (simdjson::simdjson_error& e) { |
312 | 0 | st = Status::DataQualityError("Parse json data failed. code: {}, error info: {}", |
313 | 0 | e.error(), e.what()); |
314 | 0 | } |
315 | 29 | if (!st.ok()) { |
316 | 3 | RETURN_IF_ERROR(_handle_json_error(st, file_block, original_rows, &is_empty_row)); |
317 | 3 | } |
318 | | // An ignored or empty JSON object can produce no row. Avoid spinning forever on a document |
319 | | // that was consumed but produced no materialized value. |
320 | 27 | if (!is_empty_row && file_block->rows() == original_rows) { |
321 | 10 | break; |
322 | 10 | } |
323 | 27 | } |
324 | | |
325 | 11 | *rows = file_block->rows(); |
326 | 11 | RETURN_IF_ERROR(_apply_filters(file_block, rows)); |
327 | 11 | _reader_statistics.read_rows += *rows; |
328 | 11 | *eof = _reader_eof && *rows == 0; |
329 | 11 | _eof = *eof; |
330 | 11 | return Status::OK(); |
331 | 11 | } |
332 | | |
333 | 14 | Status JsonReader::close() { |
334 | 14 | if (_line_reader != nullptr) { |
335 | 10 | _line_reader->close(); |
336 | 10 | _line_reader.reset(); |
337 | 10 | } |
338 | 14 | _json_parser.reset(); |
339 | 14 | _decompressor.reset(); |
340 | 14 | _physical_file_reader.reset(); |
341 | 14 | _tracing_file_reader.reset(); |
342 | 14 | _file_reader.reset(); |
343 | 14 | _requested_columns.clear(); |
344 | 14 | _slot_name_to_index.clear(); |
345 | 14 | _previous_positions.clear(); |
346 | 14 | _cached_string_values.clear(); |
347 | 14 | return Status::OK(); |
348 | 14 | } |
349 | | |
350 | | Status JsonReader::_build_requested_columns(const FileScanRequest& request, |
351 | 15 | std::vector<RequestedColumn>* columns) const { |
352 | 15 | DORIS_CHECK(columns != nullptr); |
353 | 15 | columns->clear(); |
354 | | // FileScanRequest stores a map from file-local id to output block position. Materialization is |
355 | | // position-driven, so normalize it into a dense vector ordered by block position while keeping |
356 | | // the original source index for jsonpaths. |
357 | 15 | std::vector<RequestedColumn> by_position(request.local_positions.size()); |
358 | 28 | for (const auto& [file_column_id, block_position] : request.local_positions) { |
359 | 28 | if (file_column_id.value() < 0 || |
360 | 28 | static_cast<size_t>(file_column_id.value()) >= _source_file_slot_descs.size()) { |
361 | 1 | return Status::InvalidArgument("JSON v2 request references unknown local column id {}", |
362 | 1 | file_column_id.value()); |
363 | 1 | } |
364 | 27 | if (block_position.value() >= by_position.size()) { |
365 | 1 | return Status::InvalidArgument("JSON v2 request has invalid block position {}", |
366 | 1 | block_position.value()); |
367 | 1 | } |
368 | 26 | const auto source_index = cast_set<size_t>(file_column_id.value()); |
369 | 26 | RequestedColumn requested_column; |
370 | 26 | requested_column.file_column_id = file_column_id; |
371 | 26 | requested_column.block_position = block_position; |
372 | 26 | requested_column.source_index = source_index; |
373 | 26 | requested_column.slot_desc = _source_file_slot_descs[source_index]; |
374 | 26 | requested_column.serde = _source_serdes[source_index]; |
375 | 26 | by_position[block_position.value()] = std::move(requested_column); |
376 | 26 | } |
377 | 37 | for (size_t pos = 0; pos < by_position.size(); ++pos) { |
378 | 25 | if (!by_position[pos].file_column_id.is_valid()) { |
379 | 1 | return Status::InvalidArgument("JSON v2 request misses block position {}", pos); |
380 | 1 | } |
381 | 25 | } |
382 | 12 | *columns = std::move(by_position); |
383 | 12 | return Status::OK(); |
384 | 13 | } |
385 | | |
386 | 12 | TFileRangeDesc JsonReader::_json_range() const { |
387 | 12 | auto range = _range; |
388 | 12 | range.__set_path(_file_description->path); |
389 | 12 | range.__set_start_offset(_file_description->range_start_offset); |
390 | 12 | range.__set_size(_file_description->range_size); |
391 | 12 | if (_file_description->file_size >= 0) { |
392 | 12 | range.__set_file_size(_file_description->file_size); |
393 | 12 | } |
394 | 12 | if (!_file_description->fs_name.empty()) { |
395 | 0 | range.__set_fs_name(_file_description->fs_name); |
396 | 0 | } |
397 | 12 | range.__set_file_cache_admission(_file_description->file_cache_admission); |
398 | 12 | if (_range_compress_type != TFileCompressType::UNKNOWN) { |
399 | 0 | range.__set_compress_type(_range_compress_type); |
400 | 0 | } |
401 | 12 | if (_stream_load_id.has_value()) { |
402 | 0 | range.__set_load_id(*_stream_load_id); |
403 | 0 | } |
404 | 12 | return range; |
405 | 12 | } |
406 | | |
407 | 12 | Status JsonReader::_open_file_reader() { |
408 | 12 | _current_offset = _reader_range.start_offset; |
409 | 12 | if (_current_offset != 0) { |
410 | 0 | --_current_offset; |
411 | 0 | } |
412 | 12 | if (_scan_params->file_type == TFileType::FILE_STREAM) { |
413 | 0 | if (!_stream_load_id.has_value()) { |
414 | 0 | return Status::InvalidArgument("JSON v2 stream reader requires load id"); |
415 | 0 | } |
416 | 0 | RETURN_IF_ERROR(FileFactory::create_pipe_reader(*_stream_load_id, &_physical_file_reader, |
417 | 0 | _runtime_state, /*need_schema=*/false)); |
418 | 12 | } else { |
419 | 12 | _file_description->mtime = |
420 | 12 | _reader_range.__isset.modification_time ? _reader_range.modification_time : 0; |
421 | 12 | auto reader_options = FileFactory::get_reader_options(_runtime_state->query_options(), |
422 | 12 | *_file_description); |
423 | 12 | auto file_reader = DORIS_TRY(FileFactory::create_file_reader( |
424 | 12 | *_system_properties, *_file_description, reader_options, _profile)); |
425 | 12 | _physical_file_reader = |
426 | 12 | _io_ctx && _io_ctx->file_reader_stats |
427 | 12 | ? std::make_shared<io::TracingFileReader>(std::move(file_reader), |
428 | 0 | _io_ctx->file_reader_stats) |
429 | 12 | : file_reader; |
430 | 12 | } |
431 | 12 | _file_reader = _physical_file_reader; |
432 | 12 | _tracing_file_reader = _physical_file_reader; |
433 | 12 | return Status::OK(); |
434 | 12 | } |
435 | | |
436 | 12 | Status JsonReader::_create_decompressor() { |
437 | 12 | return Decompressor::create_decompressor(_file_compress_type, &_decompressor); |
438 | 12 | } |
439 | | |
440 | 10 | Status JsonReader::_create_line_reader() { |
441 | 10 | int64_t size = _reader_range.size; |
442 | 10 | if (_reader_range.start_offset != 0) { |
443 | | // Start one byte earlier and discard the first partial line, matching split semantics used |
444 | | // by text readers. |
445 | 0 | ++size; |
446 | 0 | _skip_first_line = true; |
447 | 10 | } else { |
448 | 10 | _skip_first_line = false; |
449 | 10 | } |
450 | 10 | _line_reader = NewPlainTextLineReader::create_unique( |
451 | 10 | _profile, _physical_file_reader, _decompressor.get(), |
452 | 10 | std::make_shared<PlainTextLineReaderCtx>(_line_delimiter, _line_delimiter_length, |
453 | 10 | false), |
454 | 10 | size, _current_offset); |
455 | 10 | return Status::OK(); |
456 | 10 | } |
457 | | |
458 | 12 | Status JsonReader::_parse_jsonpath_and_json_root() { |
459 | 12 | _parsed_jsonpaths.clear(); |
460 | 12 | _parsed_json_root.clear(); |
461 | 12 | if (!_jsonpaths.empty()) { |
462 | 2 | rapidjson::Document jsonpaths_doc; |
463 | 2 | if (jsonpaths_doc.Parse(_jsonpaths.c_str(), _jsonpaths.length()).HasParseError() || |
464 | 2 | !jsonpaths_doc.IsArray()) { |
465 | 0 | return Status::InvalidJsonPath("Invalid json path: {}", _jsonpaths); |
466 | 0 | } |
467 | 6 | for (int i = 0; i < jsonpaths_doc.Size(); ++i) { |
468 | 4 | const rapidjson::Value& path = jsonpaths_doc[i]; |
469 | 4 | if (!path.IsString()) { |
470 | 0 | return Status::InvalidJsonPath("Invalid json path: {}", _jsonpaths); |
471 | 0 | } |
472 | 4 | std::string json_path = path.GetString(); |
473 | 4 | if (json_path.size() == 1 && json_path[0] == '$') { |
474 | 0 | json_path.insert(1, "."); |
475 | 0 | } |
476 | 4 | std::vector<JsonPath> parsed_paths; |
477 | 4 | JsonFunctions::parse_json_paths(json_path, &parsed_paths); |
478 | 4 | _parsed_jsonpaths.push_back(std::move(parsed_paths)); |
479 | 4 | } |
480 | 2 | } |
481 | 12 | if (!_json_root.empty()) { |
482 | 1 | std::string json_root = _json_root; |
483 | 1 | if (json_root.size() == 1 && json_root[0] == '$') { |
484 | 0 | json_root.insert(1, "."); |
485 | 0 | } |
486 | 1 | JsonFunctions::parse_json_paths(json_root, &_parsed_json_root); |
487 | 1 | } |
488 | 12 | return Status::OK(); |
489 | 12 | } |
490 | | |
491 | 29 | Status JsonReader::_read_one_document(size_t* size, bool* eof) { |
492 | 29 | DORIS_CHECK(size != nullptr); |
493 | 29 | DORIS_CHECK(eof != nullptr); |
494 | 29 | *size = 0; |
495 | 29 | *eof = false; |
496 | 29 | if (_line_reader != nullptr) { |
497 | 25 | const uint8_t* line = nullptr; |
498 | 25 | RETURN_IF_ERROR(_line_reader->read_line(&line, size, eof, _io_ctx.get())); |
499 | 25 | if (*eof) { |
500 | 8 | return Status::OK(); |
501 | 8 | } |
502 | 17 | _document_buffer.assign(reinterpret_cast<const char*>(line), *size); |
503 | 17 | return Status::OK(); |
504 | 25 | } |
505 | | // Non-line mode treats the split as one JSON document. This supports a single object or an |
506 | | // array with strip_outer_array=true. |
507 | 4 | if (_single_document_read) { |
508 | 2 | *eof = true; |
509 | 2 | return Status::OK(); |
510 | 2 | } |
511 | 2 | _single_document_read = true; |
512 | 2 | if (_scan_params->file_type == TFileType::FILE_STREAM) { |
513 | 0 | return _read_one_document_from_pipe(size); |
514 | 0 | } |
515 | | |
516 | 2 | auto read_size = _reader_range.size; |
517 | 2 | if (read_size <= 0 && _reader_range.__isset.file_size) { |
518 | 0 | read_size = _reader_range.file_size - _current_offset; |
519 | 0 | } |
520 | 2 | if (read_size <= 0) { |
521 | 0 | *eof = true; |
522 | 0 | return Status::OK(); |
523 | 0 | } |
524 | 2 | _document_buffer.resize(cast_set<size_t>(read_size)); |
525 | 2 | Slice result(_document_buffer.data(), _document_buffer.size()); |
526 | 2 | RETURN_IF_ERROR(_physical_file_reader->read_at(_current_offset, result, size, _io_ctx.get())); |
527 | 2 | _document_buffer.resize(*size); |
528 | 2 | if (*size == 0) { |
529 | 0 | *eof = true; |
530 | 0 | } |
531 | 2 | return Status::OK(); |
532 | 2 | } |
533 | | |
534 | 0 | Status JsonReader::_read_one_document_from_pipe(size_t* read_size) { |
535 | 0 | auto* stream_load_pipe = dynamic_cast<io::StreamLoadPipe*>(_physical_file_reader.get()); |
536 | 0 | if (stream_load_pipe == nullptr) { |
537 | 0 | return Status::InternalError("JSON v2 stream reader requires StreamLoadPipe"); |
538 | 0 | } |
539 | 0 | DorisUniqueBufferPtr<uint8_t> file_buf; |
540 | 0 | RETURN_IF_ERROR(stream_load_pipe->read_one_message(&file_buf, read_size)); |
541 | 0 | _document_buffer.assign(reinterpret_cast<const char*>(file_buf.get()), *read_size); |
542 | 0 | if (!stream_load_pipe->is_chunked_transfer()) { |
543 | 0 | return Status::OK(); |
544 | 0 | } |
545 | | |
546 | 0 | while (true) { |
547 | 0 | DorisUniqueBufferPtr<uint8_t> next_buf; |
548 | 0 | size_t next_size = 0; |
549 | 0 | RETURN_IF_ERROR(stream_load_pipe->read_one_message(&next_buf, &next_size)); |
550 | 0 | if (next_size == 0) { |
551 | 0 | break; |
552 | 0 | } |
553 | 0 | _document_buffer.append(reinterpret_cast<const char*>(next_buf.get()), next_size); |
554 | 0 | *read_size += next_size; |
555 | 0 | } |
556 | 0 | return Status::OK(); |
557 | 0 | } |
558 | | |
559 | 29 | Status JsonReader::_parse_next_json(size_t* size, bool* eof) { |
560 | 29 | RETURN_IF_ERROR(_read_one_document(size, eof)); |
561 | 29 | if (*eof || *size == 0) { |
562 | 11 | return Status::OK(); |
563 | 11 | } |
564 | 18 | if (*size >= 3 && static_cast<unsigned char>(_document_buffer[0]) == 0xEF && |
565 | 18 | static_cast<unsigned char>(_document_buffer[1]) == 0xBB && |
566 | 18 | static_cast<unsigned char>(_document_buffer[2]) == 0xBF) { |
567 | 0 | _document_buffer.erase(0, 3); |
568 | 0 | *size -= 3; |
569 | 0 | } |
570 | 18 | if (*size + simdjson::SIMDJSON_PADDING > _padded_size) { |
571 | 0 | _padded_size = *size + simdjson::SIMDJSON_PADDING; |
572 | 0 | _padding_buffer.resize(_padded_size); |
573 | 0 | } |
574 | | // Ondemand values reference the input buffer. Keep the padded bytes in a member buffer until the |
575 | | // current document is fully materialized. |
576 | 18 | std::memcpy(_padding_buffer.data(), _document_buffer.data(), *size); |
577 | 18 | _original_doc_size = *size; |
578 | 18 | const auto error = |
579 | 18 | _json_parser->iterate(std::string_view(_padding_buffer.data(), *size), _padded_size) |
580 | 18 | .get(_original_json_doc); |
581 | 18 | if (error != simdjson::error_code::SUCCESS) { |
582 | 0 | return Status::DataQualityError( |
583 | 0 | "Parse json data for JsonDoc failed. code: {}, error info: {}", error, |
584 | 0 | simdjson::error_message(error)); |
585 | 0 | } |
586 | 18 | return Status::OK(); |
587 | 18 | } |
588 | | |
589 | 18 | Status JsonReader::_extract_json_value(size_t size, bool* eof, bool* is_empty_row) { |
590 | 18 | DORIS_CHECK(eof != nullptr); |
591 | 18 | DORIS_CHECK(is_empty_row != nullptr); |
592 | 18 | *is_empty_row = false; |
593 | 18 | if (size == 0 || *eof) { |
594 | 0 | *is_empty_row = true; |
595 | 0 | return Status::OK(); |
596 | 0 | } |
597 | 18 | auto type_res = _original_json_doc.type(); |
598 | 18 | if (type_res.error() != simdjson::error_code::SUCCESS) { |
599 | 0 | return Status::DataQualityError( |
600 | 0 | "Parse json data for JsonDoc failed. code: {}, error info: {}", type_res.error(), |
601 | 0 | simdjson::error_message(type_res.error())); |
602 | 0 | } |
603 | 18 | const auto type = type_res.value(); |
604 | 18 | if (type != simdjson::ondemand::json_type::object && |
605 | 18 | type != simdjson::ondemand::json_type::array) { |
606 | 2 | return Status::DataQualityError("Not an json object or json array"); |
607 | 2 | } |
608 | 16 | _parsed_from_json_root = false; |
609 | 16 | if (!_parsed_json_root.empty() && type == simdjson::ondemand::json_type::object) { |
610 | | // In object mode json_root can be applied once here. In outer-array mode each array element |
611 | | // needs its own root extraction, which is handled while iterating the array. |
612 | 2 | simdjson::ondemand::object object = _original_json_doc; |
613 | 2 | Status st = JsonFunctions::extract_from_object(object, _parsed_json_root, &_json_value); |
614 | 2 | if (!st.ok()) { |
615 | 0 | return Status::DataQualityError("{}", st.to_string()); |
616 | 0 | } |
617 | 2 | _parsed_from_json_root = true; |
618 | 14 | } else { |
619 | 14 | _json_value = _original_json_doc; |
620 | 14 | } |
621 | | |
622 | 16 | const auto value_type = _json_value.type().value(); |
623 | 16 | if (value_type == simdjson::ondemand::json_type::array && !_strip_outer_array) { |
624 | 0 | return Status::DataQualityError( |
625 | 0 | "JSON data is array-object, `strip_outer_array` must be TRUE."); |
626 | 0 | } |
627 | 16 | if (value_type != simdjson::ondemand::json_type::array && _strip_outer_array) { |
628 | 0 | return Status::DataQualityError( |
629 | 0 | "JSON data is not an array-object, `strip_outer_array` must be FALSE."); |
630 | 0 | } |
631 | 16 | if (!_parsed_jsonpaths.empty() && _strip_outer_array && |
632 | 16 | _json_value.count_elements().value() == 0) { |
633 | 0 | *is_empty_row = true; |
634 | 0 | } |
635 | 16 | return Status::OK(); |
636 | 16 | } |
637 | | |
638 | 16 | Status JsonReader::_append_rows_from_current_value(Block* block, bool* is_empty_row, bool* eof) { |
639 | 16 | if (_parsed_jsonpaths.empty()) { |
640 | 13 | return _append_simple_json_rows(block, is_empty_row, eof); |
641 | 13 | } |
642 | 3 | if (_strip_outer_array) { |
643 | 1 | return _append_flat_array_jsonpath_rows(block, is_empty_row, eof); |
644 | 1 | } |
645 | 2 | return _append_nested_jsonpath_row(block, is_empty_row, eof); |
646 | 3 | } |
647 | | |
648 | 13 | Status JsonReader::_append_simple_json_rows(Block* block, bool* is_empty_row, bool* eof) { |
649 | 13 | DORIS_CHECK(block != nullptr); |
650 | 13 | DORIS_CHECK(is_empty_row != nullptr); |
651 | 13 | DORIS_CHECK(eof != nullptr); |
652 | 13 | bool valid = false; |
653 | 13 | if (_json_value.type().value() == simdjson::ondemand::json_type::array) { |
654 | 1 | _array = _json_value.get_array(); |
655 | 1 | if (_array.count_elements() == 0) { |
656 | 0 | *is_empty_row = true; |
657 | 0 | return Status::OK(); |
658 | 0 | } |
659 | 1 | _array_iter = _array.begin(); |
660 | 3 | while (_array_iter != _array.end()) { |
661 | 2 | simdjson::ondemand::object object_value = (*_array_iter).get_object(); |
662 | 2 | RETURN_IF_ERROR(_set_column_values_from_object(&object_value, block, &valid)); |
663 | 2 | ++_array_iter; |
664 | 2 | if (!valid) { |
665 | 0 | *is_empty_row = true; |
666 | 0 | return Status::OK(); |
667 | 0 | } |
668 | 2 | } |
669 | 12 | } else { |
670 | 12 | simdjson::ondemand::object object_value = _json_value.get_object(); |
671 | 12 | RETURN_IF_ERROR(_set_column_values_from_object(&object_value, block, &valid)); |
672 | 11 | if (!valid) { |
673 | 0 | *is_empty_row = true; |
674 | 0 | return Status::OK(); |
675 | 0 | } |
676 | 11 | } |
677 | 12 | *is_empty_row = false; |
678 | 12 | return Status::OK(); |
679 | 13 | } |
680 | | |
681 | 1 | Status JsonReader::_append_flat_array_jsonpath_rows(Block* block, bool* is_empty_row, bool* eof) { |
682 | 1 | DORIS_CHECK(block != nullptr); |
683 | 1 | DORIS_CHECK(is_empty_row != nullptr); |
684 | 1 | DORIS_CHECK(eof != nullptr); |
685 | 1 | const size_t original_rows = block->rows(); |
686 | 1 | bool valid = true; |
687 | 1 | _array = _json_value.get_array(); |
688 | 1 | _array_iter = _array.begin(); |
689 | 3 | while (_array_iter != _array.end()) { |
690 | 2 | simdjson::ondemand::object object_value = (*_array_iter).get_object(); |
691 | 2 | if (!_parsed_from_json_root && !_parsed_json_root.empty()) { |
692 | | // For strip_outer_array, json_root is evaluated against each element. Elements without |
693 | | // the requested root do not produce rows, matching the load reader behavior. |
694 | 0 | simdjson::ondemand::value rooted_value; |
695 | 0 | Status st = JsonFunctions::extract_from_object(object_value, _parsed_json_root, |
696 | 0 | &rooted_value); |
697 | 0 | if (!st.ok()) { |
698 | 0 | if (st.is<ErrorCode::NOT_FOUND>()) { |
699 | 0 | ++_array_iter; |
700 | 0 | continue; |
701 | 0 | } |
702 | 0 | return st; |
703 | 0 | } |
704 | 0 | if (rooted_value.type().value() != simdjson::ondemand::json_type::object) { |
705 | 0 | ++_array_iter; |
706 | 0 | continue; |
707 | 0 | } |
708 | 0 | object_value = rooted_value.get_object(); |
709 | 0 | } |
710 | 2 | RETURN_IF_ERROR(_write_columns_by_jsonpath(&object_value, block, &valid)); |
711 | 2 | ++_array_iter; |
712 | 2 | } |
713 | 1 | *is_empty_row = block->rows() == original_rows; |
714 | 1 | return Status::OK(); |
715 | 1 | } |
716 | | |
717 | 2 | Status JsonReader::_append_nested_jsonpath_row(Block* block, bool* is_empty_row, bool* eof) { |
718 | 2 | DORIS_CHECK(block != nullptr); |
719 | 2 | DORIS_CHECK(is_empty_row != nullptr); |
720 | 2 | DORIS_CHECK(eof != nullptr); |
721 | 2 | if (_json_value.type().value() != simdjson::ondemand::json_type::object) { |
722 | 0 | return Status::DataQualityError("Not object item"); |
723 | 0 | } |
724 | 2 | bool valid = true; |
725 | 2 | simdjson::ondemand::object object_value = _json_value.get_object(); |
726 | 2 | RETURN_IF_ERROR(_write_columns_by_jsonpath(&object_value, block, &valid)); |
727 | 2 | *is_empty_row = !valid; |
728 | 2 | return Status::OK(); |
729 | 2 | } |
730 | | |
731 | | Status JsonReader::_set_column_values_from_object(simdjson::ondemand::object* object_value, |
732 | 14 | Block* block, bool* valid) { |
733 | 14 | DORIS_CHECK(object_value != nullptr); |
734 | 14 | DORIS_CHECK(block != nullptr); |
735 | 14 | DORIS_CHECK(valid != nullptr); |
736 | 14 | std::vector<bool> seen_columns(block->columns(), false); |
737 | 14 | const size_t cur_row_count = block->rows(); |
738 | 14 | bool has_valid_value = false; |
739 | 14 | size_t key_index = 0; |
740 | | |
741 | 26 | for (auto field : *object_value) { |
742 | 26 | std::string_view key = field.unescaped_key().value(); |
743 | 26 | const size_t column_index = _column_index(key, key_index++); |
744 | 26 | if (column_index == static_cast<size_t>(-1)) { |
745 | 0 | continue; |
746 | 0 | } |
747 | 26 | if (seen_columns[column_index]) { |
748 | 0 | if (_is_hive_table) { |
749 | | // Hive JSON keeps the last duplicate key ignoring case. The earlier value has |
750 | | // already been appended, so remove it before writing the replacement. |
751 | 0 | _pop_back_last_inserted_value(block, column_index); |
752 | 0 | } else { |
753 | 0 | continue; |
754 | 0 | } |
755 | 0 | } |
756 | 26 | simdjson::ondemand::value value = field.value().value(); |
757 | 26 | const auto& requested = _requested_columns[column_index]; |
758 | 26 | auto* column_ptr = block->get_by_position(column_index).column->assert_mutable().get(); |
759 | 26 | RETURN_IF_ERROR(_write_data_to_column<false>( |
760 | 26 | value, requested.slot_desc->get_data_type_ptr(), column_ptr, |
761 | 26 | requested.slot_desc->col_name(), requested.serde, valid)); |
762 | 26 | if (!*valid) { |
763 | 0 | return Status::OK(); |
764 | 0 | } |
765 | 26 | seen_columns[column_index] = true; |
766 | 26 | has_valid_value = true; |
767 | 26 | } |
768 | | |
769 | 41 | for (size_t i = 0; i < _requested_columns.size(); ++i) { |
770 | 28 | if (seen_columns[i]) { |
771 | 26 | continue; |
772 | 26 | } |
773 | 2 | auto* column_ptr = block->get_by_position(i).column->assert_mutable().get(); |
774 | 2 | RETURN_IF_ERROR(_fill_missing_column(_requested_columns[i], column_ptr, valid)); |
775 | 1 | if (!*valid) { |
776 | 0 | _truncate_block_to_rows(block, cur_row_count); |
777 | 0 | return Status::OK(); |
778 | 0 | } |
779 | 1 | } |
780 | 13 | *valid = true; |
781 | 13 | if (!has_valid_value) { |
782 | 0 | return Status::OK(); |
783 | 0 | } |
784 | 13 | return Status::OK(); |
785 | 13 | } |
786 | | |
787 | | Status JsonReader::_write_columns_by_jsonpath(simdjson::ondemand::object* object_value, |
788 | 4 | Block* block, bool* valid) { |
789 | 4 | DORIS_CHECK(object_value != nullptr); |
790 | 4 | DORIS_CHECK(block != nullptr); |
791 | 4 | DORIS_CHECK(valid != nullptr); |
792 | 4 | bool has_valid_value = false; |
793 | 4 | const size_t cur_row_count = block->rows(); |
794 | 4 | _cached_string_values.clear(); |
795 | | |
796 | 12 | for (size_t i = 0; i < _requested_columns.size(); ++i) { |
797 | 8 | const auto& requested = _requested_columns[i]; |
798 | 8 | auto* column_ptr = block->get_by_position(i).column->assert_mutable().get(); |
799 | 8 | simdjson::ondemand::value json_value; |
800 | 8 | Status st = Status::OK(); |
801 | 8 | if (requested.source_index < _parsed_jsonpaths.size()) { |
802 | 8 | st = JsonFunctions::extract_from_object( |
803 | 8 | *object_value, _parsed_jsonpaths[requested.source_index], &json_value); |
804 | 8 | if (!st.ok() && !st.is<ErrorCode::NOT_FOUND>()) { |
805 | 0 | return st; |
806 | 0 | } |
807 | 8 | } |
808 | 8 | if (_is_root_path_for_column(requested)) { |
809 | | // A root jsonpath means "materialize the whole current JSON document" instead of a |
810 | | // field under it. Use the original bytes so callers receive the same document text. |
811 | 0 | if (is_column_nullable(*column_ptr)) { |
812 | 0 | auto* nullable_column = assert_cast<ColumnNullable*>(column_ptr); |
813 | 0 | nullable_column->get_null_map_data().push_back(0); |
814 | 0 | auto* column_string = |
815 | 0 | assert_cast<ColumnString*>(nullable_column->get_nested_column_ptr().get()); |
816 | 0 | column_string->insert_data(_padding_buffer.data(), _original_doc_size); |
817 | 0 | } else { |
818 | 0 | auto* column_string = assert_cast<ColumnString*>(column_ptr); |
819 | 0 | column_string->insert_data(_padding_buffer.data(), _original_doc_size); |
820 | 0 | } |
821 | 0 | has_valid_value = true; |
822 | 8 | } else if (requested.source_index >= _parsed_jsonpaths.size() || |
823 | 8 | st.is<ErrorCode::NOT_FOUND>()) { |
824 | 0 | RETURN_IF_ERROR(_fill_missing_column(requested, column_ptr, valid)); |
825 | 0 | if (!*valid) { |
826 | 0 | _truncate_block_to_rows(block, cur_row_count); |
827 | 0 | return Status::OK(); |
828 | 0 | } |
829 | 8 | } else { |
830 | 8 | RETURN_IF_ERROR(_write_data_to_column<true>( |
831 | 8 | json_value, requested.slot_desc->get_data_type_ptr(), column_ptr, |
832 | 8 | requested.slot_desc->col_name(), requested.serde, valid)); |
833 | 8 | if (!*valid) { |
834 | 0 | _truncate_block_to_rows(block, cur_row_count); |
835 | 0 | return Status::OK(); |
836 | 0 | } |
837 | 8 | has_valid_value = true; |
838 | 8 | } |
839 | 8 | } |
840 | | |
841 | 4 | if (!has_valid_value) { |
842 | | // jsonpaths can legally match nothing. Roll the row back so an all-missing path set does |
843 | | // not create a synthetic row of nulls. |
844 | 0 | _truncate_block_to_rows(block, cur_row_count); |
845 | 0 | *valid = false; |
846 | 0 | return Status::OK(); |
847 | 0 | } |
848 | 4 | *valid = true; |
849 | 4 | return Status::OK(); |
850 | 4 | } |
851 | | |
852 | | template <bool use_string_cache> |
853 | | Status JsonReader::_write_data_to_column(simdjson::ondemand::value& value, |
854 | | const DataTypePtr& type_desc, IColumn* column_ptr, |
855 | | const std::string& column_name, |
856 | 34 | const DataTypeSerDeSPtr& serde, bool* valid) { |
857 | 34 | ColumnNullable* nullable_column = nullptr; |
858 | 34 | IColumn* data_column_ptr = column_ptr; |
859 | 34 | DataTypeSerDeSPtr data_serde = serde; |
860 | 34 | const auto value_type = value.type().value(); |
861 | | |
862 | 34 | if (is_column_nullable(*column_ptr)) { |
863 | 33 | nullable_column = assert_cast<ColumnNullable*>(column_ptr); |
864 | 33 | data_column_ptr = nullable_column->get_nested_column().get_ptr().get(); |
865 | 33 | if (type_desc->is_nullable()) { |
866 | 33 | data_serde = serde->get_nested_serdes()[0]; |
867 | 33 | } |
868 | 33 | if (value_type == simdjson::ondemand::json_type::null) { |
869 | 0 | nullable_column->insert_default(); |
870 | 0 | *valid = true; |
871 | 0 | return Status::OK(); |
872 | 0 | } |
873 | 33 | } else if (value_type == simdjson::ondemand::json_type::null) { |
874 | 0 | return Status::DataQualityError("Json value is null, but the column `{}` is not nullable.", |
875 | 0 | column_name); |
876 | 0 | } |
877 | | |
878 | 34 | const auto primitive_type = type_desc->get_primitive_type(); |
879 | 34 | if (!is_complex_type(primitive_type)) { |
880 | 34 | if (value_type == simdjson::ondemand::json_type::string) { |
881 | 16 | std::string_view value_string; |
882 | 16 | if constexpr (use_string_cache) { |
883 | 4 | const auto cache_key = value.raw_json().value(); |
884 | 4 | if (_cached_string_values.contains(cache_key)) { |
885 | 0 | value_string = _cached_string_values[cache_key]; |
886 | 4 | } else { |
887 | 4 | value_string = value.get_string(); |
888 | 4 | _cached_string_values.emplace(cache_key, value_string); |
889 | 4 | } |
890 | 12 | } else { |
891 | 12 | value_string = value.get_string(); |
892 | 12 | } |
893 | 16 | Slice slice {value_string.data(), value_string.size()}; |
894 | 16 | RETURN_IF_ERROR(data_serde->deserialize_one_cell_from_json(*data_column_ptr, slice, |
895 | 16 | _serde_options)); |
896 | 18 | } else if (value_type == simdjson::ondemand::json_type::boolean) { |
897 | 0 | const char* str_value = value.get_bool() ? "1" : "0"; |
898 | 0 | Slice slice {str_value, 1}; |
899 | 0 | RETURN_IF_ERROR(data_serde->deserialize_one_cell_from_json(*data_column_ptr, slice, |
900 | 0 | _serde_options)); |
901 | 18 | } else { |
902 | 18 | std::string_view json_str = simdjson::to_json_string(value); |
903 | 18 | Slice slice {json_str.data(), json_str.size()}; |
904 | 18 | RETURN_IF_ERROR(data_serde->deserialize_one_cell_from_json(*data_column_ptr, slice, |
905 | 18 | _serde_options)); |
906 | 18 | } |
907 | 34 | } else if (primitive_type == TYPE_STRUCT) { |
908 | 0 | if (value_type != simdjson::ondemand::json_type::object) { |
909 | 0 | return Status::DataQualityError( |
910 | 0 | "Json value isn't object, but the column `{}` is struct.", column_name); |
911 | 0 | } |
912 | 0 | const auto* type_struct = |
913 | 0 | assert_cast<const DataTypeStruct*>(remove_nullable(type_desc).get()); |
914 | 0 | auto* struct_column_ptr = assert_cast<ColumnStruct*>(data_column_ptr); |
915 | 0 | const auto sub_serdes = data_serde->get_nested_serdes(); |
916 | 0 | std::map<std::string, size_t> sub_col_name_to_idx; |
917 | 0 | for (size_t sub_col_idx = 0; sub_col_idx < type_struct->get_elements().size(); |
918 | 0 | ++sub_col_idx) { |
919 | 0 | sub_col_name_to_idx.emplace(lower_key(type_struct->get_element_name(sub_col_idx)), |
920 | 0 | sub_col_idx); |
921 | 0 | } |
922 | 0 | std::vector<bool> has_value(type_struct->get_elements().size(), false); |
923 | 0 | simdjson::ondemand::object struct_value = value.get_object(); |
924 | 0 | for (auto sub : struct_value) { |
925 | 0 | const auto sub_key = lower_key(sub.unescaped_key().value()); |
926 | 0 | const auto it = sub_col_name_to_idx.find(sub_key); |
927 | 0 | if (it == sub_col_name_to_idx.end()) { |
928 | 0 | continue; |
929 | 0 | } |
930 | 0 | const auto sub_column_idx = it->second; |
931 | 0 | auto sub_column_ptr = struct_column_ptr->get_column(sub_column_idx).get_ptr(); |
932 | 0 | if (has_value[sub_column_idx]) { |
933 | | // Struct fields follow Hive-style duplicate handling: the last matching nested key |
934 | | // wins. Remove the earlier nested value before appending the new one. |
935 | 0 | sub_column_ptr->pop_back(1); |
936 | 0 | } |
937 | 0 | has_value[sub_column_idx] = true; |
938 | 0 | auto sub_value = sub.value().value(); |
939 | 0 | RETURN_IF_ERROR(_write_data_to_column<use_string_cache>( |
940 | 0 | sub_value, type_struct->get_element(sub_column_idx), sub_column_ptr.get(), |
941 | 0 | column_name + "." + sub_key, sub_serdes[sub_column_idx], valid)); |
942 | 0 | } |
943 | 0 | for (size_t sub_col_idx = 0; sub_col_idx < type_struct->get_elements().size(); |
944 | 0 | ++sub_col_idx) { |
945 | 0 | if (has_value[sub_col_idx]) { |
946 | 0 | continue; |
947 | 0 | } |
948 | 0 | auto sub_column_ptr = struct_column_ptr->get_column(sub_col_idx).get_ptr(); |
949 | 0 | if (!is_column_nullable(*sub_column_ptr)) { |
950 | 0 | return Status::DataQualityError( |
951 | 0 | "Json file structColumn miss field {} and this column isn't nullable.", |
952 | 0 | column_name + "." + type_struct->get_element_name(sub_col_idx)); |
953 | 0 | } |
954 | 0 | sub_column_ptr->insert_default(); |
955 | 0 | } |
956 | 0 | } else if (primitive_type == TYPE_MAP) { |
957 | 0 | if (value_type != simdjson::ondemand::json_type::object) { |
958 | 0 | return Status::DataQualityError("Json value isn't object, but the column `{}` is map.", |
959 | 0 | column_name); |
960 | 0 | } |
961 | 0 | const auto* map_type = assert_cast<const DataTypeMap*>(remove_nullable(type_desc).get()); |
962 | 0 | auto* map_column_ptr = assert_cast<ColumnMap*>(data_column_ptr); |
963 | 0 | const auto sub_serdes = data_serde->get_nested_serdes(); |
964 | 0 | size_t field_count = 0; |
965 | 0 | simdjson::ondemand::object object_value = value.get_object(); |
966 | 0 | for (auto member_value : object_value) { |
967 | 0 | auto* key_column = map_column_ptr->get_keys_ptr()->assert_mutable()->get_ptr().get(); |
968 | 0 | auto key_serde = sub_serdes[0]; |
969 | 0 | if (is_column_nullable(*key_column)) { |
970 | 0 | auto* nullable_key = assert_cast<ColumnNullable*>(key_column); |
971 | 0 | nullable_key->get_null_map_data().push_back(0); |
972 | 0 | key_column = nullable_key->get_nested_column().get_ptr().get(); |
973 | 0 | if (map_type->get_key_type()->is_nullable()) { |
974 | 0 | key_serde = key_serde->get_nested_serdes()[0]; |
975 | 0 | } |
976 | 0 | } |
977 | 0 | std::string_view key_view = member_value.unescaped_key().value(); |
978 | 0 | Slice key_slice(key_view.data(), key_view.size()); |
979 | 0 | RETURN_IF_ERROR(key_serde->deserialize_one_cell_from_json(*key_column, key_slice, |
980 | 0 | _serde_options)); |
981 | 0 | simdjson::ondemand::value field_value = member_value.value().value(); |
982 | 0 | RETURN_IF_ERROR(_write_data_to_column<use_string_cache>( |
983 | 0 | field_value, map_type->get_value_type(), |
984 | 0 | map_column_ptr->get_values_ptr()->assert_mutable()->get_ptr().get(), |
985 | 0 | column_name + ".value", sub_serdes[1], valid)); |
986 | 0 | ++field_count; |
987 | 0 | } |
988 | 0 | auto& offsets = map_column_ptr->get_offsets(); |
989 | 0 | offsets.emplace_back(offsets.back() + field_count); |
990 | 0 | } else if (primitive_type == TYPE_ARRAY) { |
991 | 0 | if (value_type != simdjson::ondemand::json_type::array) { |
992 | 0 | return Status::DataQualityError("Json value isn't array, but the column `{}` is array.", |
993 | 0 | column_name); |
994 | 0 | } |
995 | 0 | const auto* array_type = |
996 | 0 | assert_cast<const DataTypeArray*>(remove_nullable(type_desc).get()); |
997 | 0 | auto* array_column_ptr = assert_cast<ColumnArray*>(data_column_ptr); |
998 | 0 | const auto sub_serdes = data_serde->get_nested_serdes(); |
999 | 0 | size_t field_count = 0; |
1000 | 0 | simdjson::ondemand::array array_value = value.get_array(); |
1001 | 0 | for (simdjson::ondemand::value sub_value : array_value) { |
1002 | 0 | RETURN_IF_ERROR(_write_data_to_column<use_string_cache>( |
1003 | 0 | sub_value, array_type->get_nested_type(), |
1004 | 0 | array_column_ptr->get_data().get_ptr().get(), column_name + ".element", |
1005 | 0 | sub_serdes[0], valid)); |
1006 | 0 | ++field_count; |
1007 | 0 | } |
1008 | 0 | auto& offsets = array_column_ptr->get_offsets(); |
1009 | 0 | offsets.emplace_back(offsets.back() + field_count); |
1010 | 0 | } else { |
1011 | 0 | return Status::InternalError("Not support JSON value to complex column"); |
1012 | 0 | } |
1013 | | |
1014 | 34 | if (nullable_column && value_type != simdjson::ondemand::json_type::null) { |
1015 | 33 | nullable_column->get_null_map_data().push_back(0); |
1016 | 33 | } |
1017 | 34 | *valid = true; |
1018 | 34 | return Status::OK(); |
1019 | 34 | } _ZN5doris6format4json10JsonReader21_write_data_to_columnILb0EEENS_6StatusERN8simdjson8fallback8ondemand5valueERKSt10shared_ptrIKNS_9IDataTypeEEPNS_7IColumnERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSA_INS_13DataTypeSerDeEEPb Line | Count | Source | 856 | 26 | const DataTypeSerDeSPtr& serde, bool* valid) { | 857 | 26 | ColumnNullable* nullable_column = nullptr; | 858 | 26 | IColumn* data_column_ptr = column_ptr; | 859 | 26 | DataTypeSerDeSPtr data_serde = serde; | 860 | 26 | const auto value_type = value.type().value(); | 861 | | | 862 | 26 | if (is_column_nullable(*column_ptr)) { | 863 | 25 | nullable_column = assert_cast<ColumnNullable*>(column_ptr); | 864 | 25 | data_column_ptr = nullable_column->get_nested_column().get_ptr().get(); | 865 | 25 | if (type_desc->is_nullable()) { | 866 | 25 | data_serde = serde->get_nested_serdes()[0]; | 867 | 25 | } | 868 | 25 | if (value_type == simdjson::ondemand::json_type::null) { | 869 | 0 | nullable_column->insert_default(); | 870 | 0 | *valid = true; | 871 | 0 | return Status::OK(); | 872 | 0 | } | 873 | 25 | } else if (value_type == simdjson::ondemand::json_type::null) { | 874 | 0 | return Status::DataQualityError("Json value is null, but the column `{}` is not nullable.", | 875 | 0 | column_name); | 876 | 0 | } | 877 | | | 878 | 26 | const auto primitive_type = type_desc->get_primitive_type(); | 879 | 26 | if (!is_complex_type(primitive_type)) { | 880 | 26 | if (value_type == simdjson::ondemand::json_type::string) { | 881 | 12 | std::string_view value_string; | 882 | | if constexpr (use_string_cache) { | 883 | | const auto cache_key = value.raw_json().value(); | 884 | | if (_cached_string_values.contains(cache_key)) { | 885 | | value_string = _cached_string_values[cache_key]; | 886 | | } else { | 887 | | value_string = value.get_string(); | 888 | | _cached_string_values.emplace(cache_key, value_string); | 889 | | } | 890 | 12 | } else { | 891 | 12 | value_string = value.get_string(); | 892 | 12 | } | 893 | 12 | Slice slice {value_string.data(), value_string.size()}; | 894 | 12 | RETURN_IF_ERROR(data_serde->deserialize_one_cell_from_json(*data_column_ptr, slice, | 895 | 12 | _serde_options)); | 896 | 14 | } else if (value_type == simdjson::ondemand::json_type::boolean) { | 897 | 0 | const char* str_value = value.get_bool() ? "1" : "0"; | 898 | 0 | Slice slice {str_value, 1}; | 899 | 0 | RETURN_IF_ERROR(data_serde->deserialize_one_cell_from_json(*data_column_ptr, slice, | 900 | 0 | _serde_options)); | 901 | 14 | } else { | 902 | 14 | std::string_view json_str = simdjson::to_json_string(value); | 903 | 14 | Slice slice {json_str.data(), json_str.size()}; | 904 | 14 | RETURN_IF_ERROR(data_serde->deserialize_one_cell_from_json(*data_column_ptr, slice, | 905 | 14 | _serde_options)); | 906 | 14 | } | 907 | 26 | } else if (primitive_type == TYPE_STRUCT) { | 908 | 0 | if (value_type != simdjson::ondemand::json_type::object) { | 909 | 0 | return Status::DataQualityError( | 910 | 0 | "Json value isn't object, but the column `{}` is struct.", column_name); | 911 | 0 | } | 912 | 0 | const auto* type_struct = | 913 | 0 | assert_cast<const DataTypeStruct*>(remove_nullable(type_desc).get()); | 914 | 0 | auto* struct_column_ptr = assert_cast<ColumnStruct*>(data_column_ptr); | 915 | 0 | const auto sub_serdes = data_serde->get_nested_serdes(); | 916 | 0 | std::map<std::string, size_t> sub_col_name_to_idx; | 917 | 0 | for (size_t sub_col_idx = 0; sub_col_idx < type_struct->get_elements().size(); | 918 | 0 | ++sub_col_idx) { | 919 | 0 | sub_col_name_to_idx.emplace(lower_key(type_struct->get_element_name(sub_col_idx)), | 920 | 0 | sub_col_idx); | 921 | 0 | } | 922 | 0 | std::vector<bool> has_value(type_struct->get_elements().size(), false); | 923 | 0 | simdjson::ondemand::object struct_value = value.get_object(); | 924 | 0 | for (auto sub : struct_value) { | 925 | 0 | const auto sub_key = lower_key(sub.unescaped_key().value()); | 926 | 0 | const auto it = sub_col_name_to_idx.find(sub_key); | 927 | 0 | if (it == sub_col_name_to_idx.end()) { | 928 | 0 | continue; | 929 | 0 | } | 930 | 0 | const auto sub_column_idx = it->second; | 931 | 0 | auto sub_column_ptr = struct_column_ptr->get_column(sub_column_idx).get_ptr(); | 932 | 0 | if (has_value[sub_column_idx]) { | 933 | | // Struct fields follow Hive-style duplicate handling: the last matching nested key | 934 | | // wins. Remove the earlier nested value before appending the new one. | 935 | 0 | sub_column_ptr->pop_back(1); | 936 | 0 | } | 937 | 0 | has_value[sub_column_idx] = true; | 938 | 0 | auto sub_value = sub.value().value(); | 939 | 0 | RETURN_IF_ERROR(_write_data_to_column<use_string_cache>( | 940 | 0 | sub_value, type_struct->get_element(sub_column_idx), sub_column_ptr.get(), | 941 | 0 | column_name + "." + sub_key, sub_serdes[sub_column_idx], valid)); | 942 | 0 | } | 943 | 0 | for (size_t sub_col_idx = 0; sub_col_idx < type_struct->get_elements().size(); | 944 | 0 | ++sub_col_idx) { | 945 | 0 | if (has_value[sub_col_idx]) { | 946 | 0 | continue; | 947 | 0 | } | 948 | 0 | auto sub_column_ptr = struct_column_ptr->get_column(sub_col_idx).get_ptr(); | 949 | 0 | if (!is_column_nullable(*sub_column_ptr)) { | 950 | 0 | return Status::DataQualityError( | 951 | 0 | "Json file structColumn miss field {} and this column isn't nullable.", | 952 | 0 | column_name + "." + type_struct->get_element_name(sub_col_idx)); | 953 | 0 | } | 954 | 0 | sub_column_ptr->insert_default(); | 955 | 0 | } | 956 | 0 | } else if (primitive_type == TYPE_MAP) { | 957 | 0 | if (value_type != simdjson::ondemand::json_type::object) { | 958 | 0 | return Status::DataQualityError("Json value isn't object, but the column `{}` is map.", | 959 | 0 | column_name); | 960 | 0 | } | 961 | 0 | const auto* map_type = assert_cast<const DataTypeMap*>(remove_nullable(type_desc).get()); | 962 | 0 | auto* map_column_ptr = assert_cast<ColumnMap*>(data_column_ptr); | 963 | 0 | const auto sub_serdes = data_serde->get_nested_serdes(); | 964 | 0 | size_t field_count = 0; | 965 | 0 | simdjson::ondemand::object object_value = value.get_object(); | 966 | 0 | for (auto member_value : object_value) { | 967 | 0 | auto* key_column = map_column_ptr->get_keys_ptr()->assert_mutable()->get_ptr().get(); | 968 | 0 | auto key_serde = sub_serdes[0]; | 969 | 0 | if (is_column_nullable(*key_column)) { | 970 | 0 | auto* nullable_key = assert_cast<ColumnNullable*>(key_column); | 971 | 0 | nullable_key->get_null_map_data().push_back(0); | 972 | 0 | key_column = nullable_key->get_nested_column().get_ptr().get(); | 973 | 0 | if (map_type->get_key_type()->is_nullable()) { | 974 | 0 | key_serde = key_serde->get_nested_serdes()[0]; | 975 | 0 | } | 976 | 0 | } | 977 | 0 | std::string_view key_view = member_value.unescaped_key().value(); | 978 | 0 | Slice key_slice(key_view.data(), key_view.size()); | 979 | 0 | RETURN_IF_ERROR(key_serde->deserialize_one_cell_from_json(*key_column, key_slice, | 980 | 0 | _serde_options)); | 981 | 0 | simdjson::ondemand::value field_value = member_value.value().value(); | 982 | 0 | RETURN_IF_ERROR(_write_data_to_column<use_string_cache>( | 983 | 0 | field_value, map_type->get_value_type(), | 984 | 0 | map_column_ptr->get_values_ptr()->assert_mutable()->get_ptr().get(), | 985 | 0 | column_name + ".value", sub_serdes[1], valid)); | 986 | 0 | ++field_count; | 987 | 0 | } | 988 | 0 | auto& offsets = map_column_ptr->get_offsets(); | 989 | 0 | offsets.emplace_back(offsets.back() + field_count); | 990 | 0 | } else if (primitive_type == TYPE_ARRAY) { | 991 | 0 | if (value_type != simdjson::ondemand::json_type::array) { | 992 | 0 | return Status::DataQualityError("Json value isn't array, but the column `{}` is array.", | 993 | 0 | column_name); | 994 | 0 | } | 995 | 0 | const auto* array_type = | 996 | 0 | assert_cast<const DataTypeArray*>(remove_nullable(type_desc).get()); | 997 | 0 | auto* array_column_ptr = assert_cast<ColumnArray*>(data_column_ptr); | 998 | 0 | const auto sub_serdes = data_serde->get_nested_serdes(); | 999 | 0 | size_t field_count = 0; | 1000 | 0 | simdjson::ondemand::array array_value = value.get_array(); | 1001 | 0 | for (simdjson::ondemand::value sub_value : array_value) { | 1002 | 0 | RETURN_IF_ERROR(_write_data_to_column<use_string_cache>( | 1003 | 0 | sub_value, array_type->get_nested_type(), | 1004 | 0 | array_column_ptr->get_data().get_ptr().get(), column_name + ".element", | 1005 | 0 | sub_serdes[0], valid)); | 1006 | 0 | ++field_count; | 1007 | 0 | } | 1008 | 0 | auto& offsets = array_column_ptr->get_offsets(); | 1009 | 0 | offsets.emplace_back(offsets.back() + field_count); | 1010 | 0 | } else { | 1011 | 0 | return Status::InternalError("Not support JSON value to complex column"); | 1012 | 0 | } | 1013 | | | 1014 | 26 | if (nullable_column && value_type != simdjson::ondemand::json_type::null) { | 1015 | 25 | nullable_column->get_null_map_data().push_back(0); | 1016 | 25 | } | 1017 | 26 | *valid = true; | 1018 | 26 | return Status::OK(); | 1019 | 26 | } |
_ZN5doris6format4json10JsonReader21_write_data_to_columnILb1EEENS_6StatusERN8simdjson8fallback8ondemand5valueERKSt10shared_ptrIKNS_9IDataTypeEEPNS_7IColumnERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSA_INS_13DataTypeSerDeEEPb Line | Count | Source | 856 | 8 | const DataTypeSerDeSPtr& serde, bool* valid) { | 857 | 8 | ColumnNullable* nullable_column = nullptr; | 858 | 8 | IColumn* data_column_ptr = column_ptr; | 859 | 8 | DataTypeSerDeSPtr data_serde = serde; | 860 | 8 | const auto value_type = value.type().value(); | 861 | | | 862 | 8 | if (is_column_nullable(*column_ptr)) { | 863 | 8 | nullable_column = assert_cast<ColumnNullable*>(column_ptr); | 864 | 8 | data_column_ptr = nullable_column->get_nested_column().get_ptr().get(); | 865 | 8 | if (type_desc->is_nullable()) { | 866 | 8 | data_serde = serde->get_nested_serdes()[0]; | 867 | 8 | } | 868 | 8 | if (value_type == simdjson::ondemand::json_type::null) { | 869 | 0 | nullable_column->insert_default(); | 870 | 0 | *valid = true; | 871 | 0 | return Status::OK(); | 872 | 0 | } | 873 | 8 | } else if (value_type == simdjson::ondemand::json_type::null) { | 874 | 0 | return Status::DataQualityError("Json value is null, but the column `{}` is not nullable.", | 875 | 0 | column_name); | 876 | 0 | } | 877 | | | 878 | 8 | const auto primitive_type = type_desc->get_primitive_type(); | 879 | 8 | if (!is_complex_type(primitive_type)) { | 880 | 8 | if (value_type == simdjson::ondemand::json_type::string) { | 881 | 4 | std::string_view value_string; | 882 | 4 | if constexpr (use_string_cache) { | 883 | 4 | const auto cache_key = value.raw_json().value(); | 884 | 4 | if (_cached_string_values.contains(cache_key)) { | 885 | 0 | value_string = _cached_string_values[cache_key]; | 886 | 4 | } else { | 887 | 4 | value_string = value.get_string(); | 888 | 4 | _cached_string_values.emplace(cache_key, value_string); | 889 | 4 | } | 890 | | } else { | 891 | | value_string = value.get_string(); | 892 | | } | 893 | 4 | Slice slice {value_string.data(), value_string.size()}; | 894 | 4 | RETURN_IF_ERROR(data_serde->deserialize_one_cell_from_json(*data_column_ptr, slice, | 895 | 4 | _serde_options)); | 896 | 4 | } else if (value_type == simdjson::ondemand::json_type::boolean) { | 897 | 0 | const char* str_value = value.get_bool() ? "1" : "0"; | 898 | 0 | Slice slice {str_value, 1}; | 899 | 0 | RETURN_IF_ERROR(data_serde->deserialize_one_cell_from_json(*data_column_ptr, slice, | 900 | 0 | _serde_options)); | 901 | 4 | } else { | 902 | 4 | std::string_view json_str = simdjson::to_json_string(value); | 903 | 4 | Slice slice {json_str.data(), json_str.size()}; | 904 | 4 | RETURN_IF_ERROR(data_serde->deserialize_one_cell_from_json(*data_column_ptr, slice, | 905 | 4 | _serde_options)); | 906 | 4 | } | 907 | 8 | } else if (primitive_type == TYPE_STRUCT) { | 908 | 0 | if (value_type != simdjson::ondemand::json_type::object) { | 909 | 0 | return Status::DataQualityError( | 910 | 0 | "Json value isn't object, but the column `{}` is struct.", column_name); | 911 | 0 | } | 912 | 0 | const auto* type_struct = | 913 | 0 | assert_cast<const DataTypeStruct*>(remove_nullable(type_desc).get()); | 914 | 0 | auto* struct_column_ptr = assert_cast<ColumnStruct*>(data_column_ptr); | 915 | 0 | const auto sub_serdes = data_serde->get_nested_serdes(); | 916 | 0 | std::map<std::string, size_t> sub_col_name_to_idx; | 917 | 0 | for (size_t sub_col_idx = 0; sub_col_idx < type_struct->get_elements().size(); | 918 | 0 | ++sub_col_idx) { | 919 | 0 | sub_col_name_to_idx.emplace(lower_key(type_struct->get_element_name(sub_col_idx)), | 920 | 0 | sub_col_idx); | 921 | 0 | } | 922 | 0 | std::vector<bool> has_value(type_struct->get_elements().size(), false); | 923 | 0 | simdjson::ondemand::object struct_value = value.get_object(); | 924 | 0 | for (auto sub : struct_value) { | 925 | 0 | const auto sub_key = lower_key(sub.unescaped_key().value()); | 926 | 0 | const auto it = sub_col_name_to_idx.find(sub_key); | 927 | 0 | if (it == sub_col_name_to_idx.end()) { | 928 | 0 | continue; | 929 | 0 | } | 930 | 0 | const auto sub_column_idx = it->second; | 931 | 0 | auto sub_column_ptr = struct_column_ptr->get_column(sub_column_idx).get_ptr(); | 932 | 0 | if (has_value[sub_column_idx]) { | 933 | | // Struct fields follow Hive-style duplicate handling: the last matching nested key | 934 | | // wins. Remove the earlier nested value before appending the new one. | 935 | 0 | sub_column_ptr->pop_back(1); | 936 | 0 | } | 937 | 0 | has_value[sub_column_idx] = true; | 938 | 0 | auto sub_value = sub.value().value(); | 939 | 0 | RETURN_IF_ERROR(_write_data_to_column<use_string_cache>( | 940 | 0 | sub_value, type_struct->get_element(sub_column_idx), sub_column_ptr.get(), | 941 | 0 | column_name + "." + sub_key, sub_serdes[sub_column_idx], valid)); | 942 | 0 | } | 943 | 0 | for (size_t sub_col_idx = 0; sub_col_idx < type_struct->get_elements().size(); | 944 | 0 | ++sub_col_idx) { | 945 | 0 | if (has_value[sub_col_idx]) { | 946 | 0 | continue; | 947 | 0 | } | 948 | 0 | auto sub_column_ptr = struct_column_ptr->get_column(sub_col_idx).get_ptr(); | 949 | 0 | if (!is_column_nullable(*sub_column_ptr)) { | 950 | 0 | return Status::DataQualityError( | 951 | 0 | "Json file structColumn miss field {} and this column isn't nullable.", | 952 | 0 | column_name + "." + type_struct->get_element_name(sub_col_idx)); | 953 | 0 | } | 954 | 0 | sub_column_ptr->insert_default(); | 955 | 0 | } | 956 | 0 | } else if (primitive_type == TYPE_MAP) { | 957 | 0 | if (value_type != simdjson::ondemand::json_type::object) { | 958 | 0 | return Status::DataQualityError("Json value isn't object, but the column `{}` is map.", | 959 | 0 | column_name); | 960 | 0 | } | 961 | 0 | const auto* map_type = assert_cast<const DataTypeMap*>(remove_nullable(type_desc).get()); | 962 | 0 | auto* map_column_ptr = assert_cast<ColumnMap*>(data_column_ptr); | 963 | 0 | const auto sub_serdes = data_serde->get_nested_serdes(); | 964 | 0 | size_t field_count = 0; | 965 | 0 | simdjson::ondemand::object object_value = value.get_object(); | 966 | 0 | for (auto member_value : object_value) { | 967 | 0 | auto* key_column = map_column_ptr->get_keys_ptr()->assert_mutable()->get_ptr().get(); | 968 | 0 | auto key_serde = sub_serdes[0]; | 969 | 0 | if (is_column_nullable(*key_column)) { | 970 | 0 | auto* nullable_key = assert_cast<ColumnNullable*>(key_column); | 971 | 0 | nullable_key->get_null_map_data().push_back(0); | 972 | 0 | key_column = nullable_key->get_nested_column().get_ptr().get(); | 973 | 0 | if (map_type->get_key_type()->is_nullable()) { | 974 | 0 | key_serde = key_serde->get_nested_serdes()[0]; | 975 | 0 | } | 976 | 0 | } | 977 | 0 | std::string_view key_view = member_value.unescaped_key().value(); | 978 | 0 | Slice key_slice(key_view.data(), key_view.size()); | 979 | 0 | RETURN_IF_ERROR(key_serde->deserialize_one_cell_from_json(*key_column, key_slice, | 980 | 0 | _serde_options)); | 981 | 0 | simdjson::ondemand::value field_value = member_value.value().value(); | 982 | 0 | RETURN_IF_ERROR(_write_data_to_column<use_string_cache>( | 983 | 0 | field_value, map_type->get_value_type(), | 984 | 0 | map_column_ptr->get_values_ptr()->assert_mutable()->get_ptr().get(), | 985 | 0 | column_name + ".value", sub_serdes[1], valid)); | 986 | 0 | ++field_count; | 987 | 0 | } | 988 | 0 | auto& offsets = map_column_ptr->get_offsets(); | 989 | 0 | offsets.emplace_back(offsets.back() + field_count); | 990 | 0 | } else if (primitive_type == TYPE_ARRAY) { | 991 | 0 | if (value_type != simdjson::ondemand::json_type::array) { | 992 | 0 | return Status::DataQualityError("Json value isn't array, but the column `{}` is array.", | 993 | 0 | column_name); | 994 | 0 | } | 995 | 0 | const auto* array_type = | 996 | 0 | assert_cast<const DataTypeArray*>(remove_nullable(type_desc).get()); | 997 | 0 | auto* array_column_ptr = assert_cast<ColumnArray*>(data_column_ptr); | 998 | 0 | const auto sub_serdes = data_serde->get_nested_serdes(); | 999 | 0 | size_t field_count = 0; | 1000 | 0 | simdjson::ondemand::array array_value = value.get_array(); | 1001 | 0 | for (simdjson::ondemand::value sub_value : array_value) { | 1002 | 0 | RETURN_IF_ERROR(_write_data_to_column<use_string_cache>( | 1003 | 0 | sub_value, array_type->get_nested_type(), | 1004 | 0 | array_column_ptr->get_data().get_ptr().get(), column_name + ".element", | 1005 | 0 | sub_serdes[0], valid)); | 1006 | 0 | ++field_count; | 1007 | 0 | } | 1008 | 0 | auto& offsets = array_column_ptr->get_offsets(); | 1009 | 0 | offsets.emplace_back(offsets.back() + field_count); | 1010 | 0 | } else { | 1011 | 0 | return Status::InternalError("Not support JSON value to complex column"); | 1012 | 0 | } | 1013 | | | 1014 | 8 | if (nullable_column && value_type != simdjson::ondemand::json_type::null) { | 1015 | 8 | nullable_column->get_null_map_data().push_back(0); | 1016 | 8 | } | 1017 | 8 | *valid = true; | 1018 | 8 | return Status::OK(); | 1019 | 8 | } |
|
1020 | | |
1021 | | Status JsonReader::_fill_missing_column(const RequestedColumn& column, IColumn* column_ptr, |
1022 | 2 | bool* valid) { |
1023 | 2 | if (column.slot_desc->is_nullable()) { |
1024 | 1 | auto* nullable_column = assert_cast<ColumnNullable*>(column_ptr); |
1025 | 1 | nullable_column->insert_default(); |
1026 | 1 | *valid = true; |
1027 | 1 | return Status::OK(); |
1028 | 1 | } |
1029 | 1 | return Status::DataQualityError( |
1030 | 1 | "The column `{}` is not nullable, but it's not found in jsondata.", |
1031 | 1 | column.slot_desc->col_name()); |
1032 | 2 | } |
1033 | | |
1034 | 1 | Status JsonReader::_append_null_for_malformed_json(Block* block) { |
1035 | 1 | DORIS_CHECK(block != nullptr); |
1036 | 3 | for (int i = 0; i < block->columns(); ++i) { |
1037 | 2 | auto& column_with_type = block->get_by_position(i); |
1038 | 2 | if (!is_column_nullable(*column_with_type.column)) { |
1039 | 0 | return Status::DataQualityError("malformed json, but the column `{}` is not nullable.", |
1040 | 0 | column_with_type.column->get_name()); |
1041 | 0 | } |
1042 | 2 | auto column = IColumn::mutate(std::move(column_with_type.column)); |
1043 | 2 | assert_cast<ColumnNullable*>(column.get())->insert_default(); |
1044 | 2 | column_with_type.column = std::move(column); |
1045 | 2 | } |
1046 | 1 | return Status::OK(); |
1047 | 1 | } |
1048 | | |
1049 | | Status JsonReader::_handle_json_error(const Status& status, Block* block, size_t original_rows, |
1050 | 3 | bool* is_empty_row) { |
1051 | 3 | DORIS_CHECK(block != nullptr); |
1052 | 3 | DORIS_CHECK(is_empty_row != nullptr); |
1053 | | // Deserialization can fail after several columns have already appended data. Always restore the |
1054 | | // block to the row count before this document before either surfacing the error or appending |
1055 | | // the ignore-malformed null row. |
1056 | 3 | _truncate_block_to_rows(block, original_rows); |
1057 | 3 | if (_openx_json_ignore_malformed && status.is<ErrorCode::DATA_QUALITY_ERROR>()) { |
1058 | 1 | RETURN_IF_ERROR(_append_null_for_malformed_json(block)); |
1059 | 1 | *is_empty_row = false; |
1060 | 1 | return Status::OK(); |
1061 | 1 | } |
1062 | 2 | return status; |
1063 | 3 | } |
1064 | | |
1065 | 11 | Status JsonReader::_apply_filters(Block* file_block, size_t* rows) { |
1066 | 11 | return apply_materialized_reader_filters(_request.get(), _io_ctx.get(), file_block, rows); |
1067 | 11 | } |
1068 | | |
1069 | 3 | void JsonReader::_truncate_block_to_rows(Block* block, size_t num_rows) { |
1070 | 3 | DORIS_CHECK(block != nullptr); |
1071 | 9 | for (int i = 0; i < block->columns(); ++i) { |
1072 | 6 | auto& column_with_type = block->get_by_position(i); |
1073 | 6 | auto column = IColumn::mutate(std::move(column_with_type.column)); |
1074 | 6 | if (column->size() > num_rows) { |
1075 | 1 | column->pop_back(column->size() - num_rows); |
1076 | 1 | } |
1077 | 6 | column_with_type.column = std::move(column); |
1078 | 6 | } |
1079 | 3 | } |
1080 | | |
1081 | 0 | void JsonReader::_pop_back_last_inserted_value(Block* block, size_t column_index) { |
1082 | 0 | DORIS_CHECK(block != nullptr); |
1083 | 0 | auto& column = block->get_by_position(column_index).column; |
1084 | 0 | auto mutable_column = IColumn::mutate(std::move(column)); |
1085 | 0 | mutable_column->pop_back(1); |
1086 | 0 | column = std::move(mutable_column); |
1087 | 0 | } |
1088 | | |
1089 | 26 | size_t JsonReader::_column_index(std::string_view key, size_t key_index) { |
1090 | 26 | std::string hive_key; |
1091 | 26 | std::string_view lookup_key = key; |
1092 | 26 | if (_is_hive_table) { |
1093 | 0 | hive_key = lower_key(key); |
1094 | 0 | lookup_key = hive_key; |
1095 | 0 | } |
1096 | 26 | if (key_index < _previous_positions.size()) { |
1097 | | // Most JSON lines share field order. Reuse the previous line's key-position mapping before |
1098 | | // falling back to the hash table lookup. |
1099 | 10 | const auto previous = _previous_positions[key_index]; |
1100 | 10 | if (previous < _requested_columns.size()) { |
1101 | 10 | const auto previous_name = _requested_columns[previous].slot_desc->col_name(); |
1102 | 10 | if ((_is_hive_table ? lower_key(previous_name) : previous_name) == lookup_key) { |
1103 | 10 | return previous; |
1104 | 10 | } |
1105 | 10 | } |
1106 | 10 | } |
1107 | 16 | const auto it = _slot_name_to_index.find(std::string(lookup_key)); |
1108 | 16 | if (it == _slot_name_to_index.end()) { |
1109 | 0 | return static_cast<size_t>(-1); |
1110 | 0 | } |
1111 | 16 | if (key_index >= _previous_positions.size()) { |
1112 | 16 | _previous_positions.resize(key_index + 1, static_cast<size_t>(-1)); |
1113 | 16 | } |
1114 | 16 | _previous_positions[key_index] = it->second; |
1115 | 16 | return it->second; |
1116 | 16 | } |
1117 | | |
1118 | 8 | bool JsonReader::_is_root_path_for_column(const RequestedColumn& column) const { |
1119 | 8 | return column.source_index < _parsed_jsonpaths.size() && |
1120 | 8 | JsonFunctions::is_root_path(_parsed_jsonpaths[column.source_index]); |
1121 | 8 | } |
1122 | | |
1123 | | } // namespace doris::format::json |