Coverage Report

Created: 2026-06-03 09:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format/text/text_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/text/text_reader.h"
19
20
#include <gen_cpp/PlanNodes_types.h>
21
#include <gen_cpp/Types_types.h>
22
#include <glog/logging.h>
23
24
#include <cstddef>
25
#include <utility>
26
#include <vector>
27
28
#include "common/compiler_util.h" // IWYU pragma: keep
29
#include "common/status.h"
30
#include "core/block/block.h"
31
#include "exec/scan/scanner.h"
32
#include "format/csv/csv_reader.h"
33
#include "format/file_reader/new_plain_text_line_reader.h"
34
#include "format/line_reader.h"
35
#include "io/file_factory.h"
36
#include "io/fs/buffered_reader.h"
37
#include "io/fs/file_reader.h"
38
#include "io/fs/s3_file_reader.h"
39
#include "runtime/descriptors.h"
40
#include "runtime/runtime_state.h"
41
42
namespace doris {
43
44
252k
void HiveTextFieldSplitter::do_split(const Slice& line, std::vector<Slice>* splitted_values) {
45
252k
    if (_value_sep_len == 1) {
46
252k
        _split_field_single_char(line, splitted_values);
47
252k
    } else {
48
1
        _split_field_multi_char(line, splitted_values);
49
1
    }
50
252k
}
51
52
void HiveTextFieldSplitter::_split_field_single_char(const Slice& line,
53
252k
                                                     std::vector<Slice>* splitted_values) {
54
252k
    const char* data = line.data;
55
252k
    const size_t size = line.size;
56
252k
    size_t value_start = 0;
57
135M
    for (size_t i = 0; i < size; ++i) {
58
135M
        if (data[i] == _value_sep[0]) {
59
            // hive will escape the field separator in string
60
9.34M
            if (_escape_char != 0 && i > 0 && data[i - 1] == _escape_char) {
61
53
                continue;
62
53
            }
63
9.34M
            process_value_func(data, value_start, i - value_start, _trimming_char, splitted_values);
64
9.34M
            value_start = i + _value_sep_len;
65
9.34M
        }
66
135M
    }
67
252k
    process_value_func(data, value_start, size - value_start, _trimming_char, splitted_values);
68
252k
}
69
70
void HiveTextFieldSplitter::_split_field_multi_char(const Slice& line,
71
17
                                                    std::vector<Slice>* splitted_values) {
72
17
    const char* data = line.data;
73
17
    const size_t size = line.size;
74
17
    size_t start = 0;
75
76
17
    std::vector<int> next(_value_sep_len);
77
17
    next[0] = -1;
78
50
    for (int i = 1, j = -1; i < (int)_value_sep_len; i++) {
79
33
        while (j >= 0 && _value_sep[i] != _value_sep[j + 1]) {
80
0
            j = next[j];
81
0
        }
82
33
        if (_value_sep[i] == _value_sep[j + 1]) {
83
22
            j++;
84
22
        }
85
33
        next[i] = j;
86
33
    }
87
88
    // KMP search
89
198
    for (int i = 0, j = -1; i < (int)size; i++) {
90
200
        while (j >= 0 && data[i] != _value_sep[j + 1]) {
91
19
            j = next[j];
92
19
        }
93
181
        if (data[i] == _value_sep[j + 1]) {
94
90
            j++;
95
90
        }
96
181
        if (j == (int)_value_sep_len - 1) {
97
34
            size_t curpos = i - _value_sep_len + 1;
98
34
            if (_escape_char != 0 && curpos > 0 && data[curpos - 1] == _escape_char) {
99
2
                j = next[j];
100
2
                continue;
101
2
            }
102
103
32
            if (curpos >= start) {
104
25
                process_value_func(data, start, curpos - start, _trimming_char, splitted_values);
105
25
                start = curpos + _value_sep_len;
106
25
            }
107
108
32
            j = next[j];
109
32
        }
110
181
    }
111
17
    process_value_func(data, start, size - start, _trimming_char, splitted_values);
112
17
}
113
114
TextReader::TextReader(RuntimeState* state, RuntimeProfile* profile, ScannerCounter* counter,
115
                       const TFileScanRangeParams& params, const TFileRangeDesc& range,
116
                       const std::vector<SlotDescriptor*>& file_slot_descs, size_t batch_size,
117
                       io::IOContext* io_ctx, std::shared_ptr<io::IOContext> io_ctx_holder)
118
4.62k
        : CsvReader(state, profile, counter, params, range, file_slot_descs, batch_size, io_ctx,
119
4.62k
                    std::move(io_ctx_holder)) {}
120
121
4.61k
Status TextReader::_init_options() {
122
    // get column_separator and line_delimiter
123
4.61k
    _value_separator = _params.file_attributes.text_params.column_separator;
124
4.61k
    _value_separator_length = _value_separator.size();
125
4.61k
    _line_delimiter = _params.file_attributes.text_params.line_delimiter;
126
4.61k
    _line_delimiter_length = _line_delimiter.size();
127
128
4.61k
    if (_params.file_attributes.text_params.__isset.escape) {
129
3.43k
        _escape = _params.file_attributes.text_params.escape;
130
3.43k
    }
131
4.61k
    _options.escape_char = _escape;
132
133
4.61k
    _options.collection_delim = _params.file_attributes.text_params.collection_delimiter[0];
134
4.61k
    _options.map_key_delim = _params.file_attributes.text_params.mapkv_delimiter[0];
135
136
4.61k
    _options.null_format = _params.file_attributes.text_params.null_format.data();
137
4.61k
    _options.null_len = _params.file_attributes.text_params.null_format.length();
138
139
4.61k
    return Status::OK();
140
4.61k
}
141
142
6.78M
Status TextReader::_deserialize_one_cell(DataTypeSerDeSPtr serde, IColumn& column, Slice& slice) {
143
6.78M
    return serde->deserialize_one_cell_from_hive_text(column, slice, _options);
144
6.78M
}
145
146
4.61k
Status TextReader::_create_line_reader() {
147
4.61k
    std::shared_ptr<TextLineReaderContextIf> text_line_reader_ctx;
148
149
4.61k
    text_line_reader_ctx = std::make_shared<PlainTextLineReaderCtx>(_line_delimiter,
150
4.61k
                                                                    _line_delimiter_length, false);
151
152
4.61k
    _fields_splitter = std::make_unique<HiveTextFieldSplitter>(
153
4.61k
            false, false, _value_separator, _value_separator_length, -1, _escape);
154
155
4.61k
    _line_reader =
156
4.61k
            NewPlainTextLineReader::create_unique(_profile, _file_reader, _decompressor.get(),
157
4.61k
                                                  text_line_reader_ctx, _size, _start_offset);
158
159
4.61k
    return Status::OK();
160
4.61k
}
161
162
392k
Status TextReader::_validate_line(const Slice& line, bool* success) {
163
    // text file do not need utf8 check
164
392k
    *success = true;
165
392k
    return Status::OK();
166
392k
}
167
168
1.62M
Status TextReader::_deserialize_nullable_string(IColumn& column, Slice& slice) {
169
1.62M
    auto& null_column = assert_cast<ColumnNullable&>(column);
170
1.62M
    if (slice.compare(Slice(_options.null_format, _options.null_len)) == 0) {
171
1.04k
        null_column.insert_data(nullptr, 0);
172
1.04k
        return Status::OK();
173
1.04k
    }
174
1.62M
    static DataTypeStringSerDe stringSerDe(TYPE_STRING);
175
1.62M
    auto st = stringSerDe.deserialize_one_cell_from_hive_text(null_column.get_nested_column(),
176
1.62M
                                                              slice, _options);
177
1.62M
    if (!st.ok()) {
178
        // fill null if fail
179
0
        null_column.insert_data(nullptr, 0); // 0 is meaningless here
180
0
        return Status::OK();
181
0
    }
182
    // fill not null if success
183
1.62M
    null_column.get_null_map_data().push_back(0);
184
1.62M
    return Status::OK();
185
1.62M
}
186
187
} // namespace doris