Coverage Report

Created: 2026-07-23 14:25

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