Coverage Report

Created: 2026-07-06 17:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
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