Coverage Report

Created: 2026-07-24 23:23

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