Coverage Report

Created: 2026-10-15 11:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format/parquet/schema_desc.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/parquet/schema_desc.h"
19
20
#include <ctype.h>
21
22
#include <algorithm>
23
#include <ostream>
24
#include <utility>
25
26
#include "common/cast_set.h"
27
#include "common/logging.h"
28
#include "core/data_type/data_type_array.h"
29
#include "core/data_type/data_type_factory.hpp"
30
#include "core/data_type/data_type_map.h"
31
#include "core/data_type/data_type_spatial.h"
32
#include "core/data_type/data_type_struct.h"
33
#include "core/data_type/define_primitive_type.h"
34
#include "format/generic_reader.h"
35
#include "format/table/table_schema_change_helper.h"
36
#include "util/slice.h"
37
#include "util/string_util.h"
38
39
namespace doris {
40
41
2.80k
static bool is_group_node(const tparquet::SchemaElement& schema) {
42
2.80k
    return schema.num_children > 0;
43
2.80k
}
44
45
457
static bool is_list_node(const tparquet::SchemaElement& schema) {
46
457
    return schema.__isset.converted_type && schema.converted_type == tparquet::ConvertedType::LIST;
47
457
}
48
49
533
static bool is_map_node(const tparquet::SchemaElement& schema) {
50
533
    return schema.__isset.converted_type &&
51
533
           (schema.converted_type == tparquet::ConvertedType::MAP ||
52
228
            schema.converted_type == tparquet::ConvertedType::MAP_KEY_VALUE);
53
533
}
54
55
2.48k
static bool is_repeated_node(const tparquet::SchemaElement& schema) {
56
2.48k
    return schema.__isset.repetition_type &&
57
2.48k
           schema.repetition_type == tparquet::FieldRepetitionType::REPEATED;
58
2.48k
}
59
60
76
static bool is_required_node(const tparquet::SchemaElement& schema) {
61
76
    return schema.__isset.repetition_type &&
62
76
           schema.repetition_type == tparquet::FieldRepetitionType::REQUIRED;
63
76
}
64
65
2.56k
static bool is_optional_node(const tparquet::SchemaElement& schema) {
66
2.56k
    return schema.__isset.repetition_type &&
67
2.56k
           schema.repetition_type == tparquet::FieldRepetitionType::OPTIONAL;
68
2.56k
}
69
70
152
static int num_children_node(const tparquet::SchemaElement& schema) {
71
152
    return schema.__isset.num_children ? schema.num_children : 0;
72
152
}
73
74
/**
75
 * `repeated_parent_def_level` is the definition level of the first ancestor node whose repetition_type equals REPEATED.
76
 * Empty array/map values are not stored in doris columns, so have to use `repeated_parent_def_level` to skip the
77
 * empty or null values in ancestor node.
78
 *
79
 * For instance, considering an array of strings with 3 rows like the following:
80
 * null, [], [a, b, c]
81
 * We can store four elements in data column: null, a, b, c
82
 * and the offsets column is: 1, 1, 4
83
 * and the null map is: 1, 0, 0
84
 * For the i-th row in array column: range from `offsets[i - 1]` until `offsets[i]` represents the elements in this row,
85
 * so we can't store empty array/map values in doris data column.
86
 * As a comparison, spark does not require `repeated_parent_def_level`,
87
 * because the spark column stores empty array/map values , and use anther length column to indicate empty values.
88
 * Please reference: https://github.com/apache/spark/blob/master/sql/core/src/main/java/org/apache/spark/sql/execution/datasources/parquet/ParquetColumnVector.java
89
 *
90
 * Furthermore, we can also avoid store null array/map values in doris data column.
91
 * The same three rows as above, We can only store three elements in data column: a, b, c
92
 * and the offsets column is: 0, 0, 3
93
 * and the null map is: 1, 0, 0
94
 *
95
 * Inherit the repetition and definition level from parent node, if the parent node is repeated,
96
 * we should set repeated_parent_def_level = definition_level, otherwise as repeated_parent_def_level.
97
 * @param parent parent node
98
 * @param repeated_parent_def_level the first ancestor node whose repetition_type equals REPEATED
99
 */
100
533
static void set_child_node_level(FieldSchema* parent, int16_t repeated_parent_def_level) {
101
1.09k
    for (auto& child : parent->children) {
102
1.09k
        child.repetition_level = parent->repetition_level;
103
1.09k
        child.definition_level = parent->definition_level;
104
1.09k
        child.repeated_parent_def_level = repeated_parent_def_level;
105
1.09k
    }
106
533
}
107
108
152
static bool is_struct_list_node(const tparquet::SchemaElement& schema) {
109
152
    const std::string& name = schema.name;
110
152
    static const Slice array_slice("array", 5);
111
152
    static const Slice tuple_slice("_tuple", 6);
112
152
    Slice slice(name);
113
152
    return slice == array_slice || slice.ends_with(tuple_slice);
114
152
}
115
116
0
std::string FieldSchema::debug_string() const {
117
0
    std::stringstream ss;
118
0
    ss << "FieldSchema(name=" << name << ", R=" << repetition_level << ", D=" << definition_level;
119
0
    if (children.size() > 0) {
120
0
        ss << ", type=" << data_type->get_name() << ", children=[";
121
0
        for (int i = 0; i < children.size(); ++i) {
122
0
            if (i != 0) {
123
0
                ss << ", ";
124
0
            }
125
0
            ss << children[i].debug_string();
126
0
        }
127
0
        ss << "]";
128
0
    } else {
129
0
        ss << ", physical_type=" << physical_type;
130
0
        ss << " , doris_type=" << data_type->get_name();
131
0
    }
132
0
    ss << ")";
133
0
    return ss.str();
134
0
}
135
136
167
Status FieldDescriptor::parse_from_thrift(const std::vector<tparquet::SchemaElement>& t_schemas) {
137
167
    if (t_schemas.size() == 0 || !is_group_node(t_schemas[0])) {
138
0
        return Status::InvalidArgument("Wrong parquet root schema element");
139
0
    }
140
167
    const auto& root_schema = t_schemas[0];
141
167
    _fields.resize(root_schema.num_children);
142
167
    _next_schema_pos = 1;
143
144
1.63k
    for (int i = 0; i < root_schema.num_children; ++i) {
145
1.46k
        RETURN_IF_ERROR(parse_node_field(t_schemas, _next_schema_pos, &_fields[i]));
146
1.46k
        if (_name_to_field.find(_fields[i].name) != _name_to_field.end()) {
147
0
            return Status::InvalidArgument("Duplicated field name: {}", _fields[i].name);
148
0
        }
149
1.46k
        _name_to_field.emplace(_fields[i].name, &_fields[i]);
150
1.46k
    }
151
152
167
    if (_next_schema_pos != t_schemas.size()) {
153
0
        return Status::InvalidArgument("Remaining {} unparsed schema elements",
154
0
                                       t_schemas.size() - _next_schema_pos);
155
0
    }
156
157
167
    return Status::OK();
158
167
}
159
160
Status FieldDescriptor::parse_node_field(const std::vector<tparquet::SchemaElement>& t_schemas,
161
2.56k
                                         size_t curr_pos, FieldSchema* node_field) {
162
2.56k
    if (curr_pos >= t_schemas.size()) {
163
0
        return Status::InvalidArgument("Out-of-bounds index of schema elements");
164
0
    }
165
2.56k
    auto& t_schema = t_schemas[curr_pos];
166
2.56k
    if (is_group_node(t_schema)) {
167
        // nested structure or nullable list
168
533
        return parse_group_field(t_schemas, curr_pos, node_field);
169
533
    }
170
2.02k
    if (is_repeated_node(t_schema)) {
171
        // repeated <primitive-type> <name> (LIST)
172
        // produce required list<element>
173
0
        node_field->repetition_level++;
174
0
        node_field->definition_level++;
175
0
        node_field->children.resize(1);
176
0
        set_child_node_level(node_field, node_field->definition_level);
177
0
        auto child = &node_field->children[0];
178
0
        parse_physical_field(t_schema, false, child);
179
180
0
        node_field->name = t_schema.name;
181
0
        node_field->lower_case_name = to_lower(t_schema.name);
182
0
        node_field->data_type = std::make_shared<DataTypeArray>(make_nullable(child->data_type));
183
0
        _next_schema_pos = curr_pos + 1;
184
0
        node_field->field_id = t_schema.__isset.field_id ? t_schema.field_id : -1;
185
2.02k
    } else {
186
2.02k
        bool is_optional = is_optional_node(t_schema);
187
2.02k
        if (is_optional) {
188
1.86k
            node_field->definition_level++;
189
1.86k
        }
190
2.02k
        parse_physical_field(t_schema, is_optional, node_field);
191
2.02k
        _next_schema_pos = curr_pos + 1;
192
2.02k
    }
193
2.02k
    return Status::OK();
194
2.56k
}
195
196
void FieldDescriptor::parse_physical_field(const tparquet::SchemaElement& physical_schema,
197
2.02k
                                           bool is_nullable, FieldSchema* physical_field) {
198
2.02k
    physical_field->name = physical_schema.name;
199
2.02k
    physical_field->lower_case_name = to_lower(physical_field->name);
200
2.02k
    physical_field->parquet_schema = physical_schema;
201
2.02k
    physical_field->physical_type = physical_schema.type;
202
2.02k
    physical_field->column_id = UNASSIGNED_COLUMN_ID; // Initialize column_id
203
2.02k
    _physical_fields.push_back(physical_field);
204
2.02k
    physical_field->physical_column_index = cast_set<int>(_physical_fields.size() - 1);
205
2.02k
    auto type = get_doris_type(physical_schema, is_nullable);
206
2.02k
    physical_field->data_type = type.first;
207
2.02k
    physical_field->is_type_compatibility = type.second;
208
2.02k
    physical_field->field_id = physical_schema.__isset.field_id ? physical_schema.field_id : -1;
209
2.02k
}
210
211
std::pair<DataTypePtr, bool> FieldDescriptor::get_doris_type(
212
2.02k
        const tparquet::SchemaElement& physical_schema, bool nullable) {
213
2.02k
    std::pair<DataTypePtr, bool> ans = {std::make_shared<DataTypeNothing>(), false};
214
2.02k
    try {
215
2.02k
        if (physical_schema.__isset.logicalType) {
216
843
            ans = convert_to_doris_type(physical_schema.logicalType, nullable);
217
1.18k
        } else if (physical_schema.__isset.converted_type) {
218
226
            ans = convert_to_doris_type(physical_schema, nullable);
219
226
        }
220
2.02k
    } catch (...) {
221
        // now the Not supported exception are ignored
222
        // so those byte_array maybe be treated as varbinary(now) : string(before)
223
0
    }
224
2.02k
    if (ans.first->get_primitive_type() == PrimitiveType::INVALID_TYPE) {
225
960
        switch (physical_schema.type) {
226
117
        case tparquet::Type::BOOLEAN:
227
117
            ans.first = DataTypeFactory::instance().create_data_type(TYPE_BOOLEAN, nullable);
228
117
            break;
229
287
        case tparquet::Type::INT32:
230
287
            ans.first = DataTypeFactory::instance().create_data_type(TYPE_INT, nullable);
231
287
            break;
232
150
        case tparquet::Type::INT64:
233
150
            ans.first = DataTypeFactory::instance().create_data_type(TYPE_BIGINT, nullable);
234
150
            break;
235
14
        case tparquet::Type::INT96:
236
            // INT96 has no timezone annotation. A table's logical schema may override this
237
            // for known instant columns, but a catalog option cannot supply missing semantics.
238
14
            ans.first =
239
14
                    DataTypeFactory::instance().create_data_type(TYPE_DATETIMEV2, nullable, 0, 6);
240
14
            break;
241
117
        case tparquet::Type::FLOAT:
242
117
            ans.first = DataTypeFactory::instance().create_data_type(TYPE_FLOAT, nullable);
243
117
            break;
244
229
        case tparquet::Type::DOUBLE:
245
229
            ans.first = DataTypeFactory::instance().create_data_type(TYPE_DOUBLE, nullable);
246
229
            break;
247
46
        case tparquet::Type::BYTE_ARRAY:
248
46
            if (_enable_mapping_varbinary) {
249
                // if physical_schema not set logicalType and converted_type,
250
                // we treat BYTE_ARRAY as VARBINARY by default, so that we can read all data directly.
251
22
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_VARBINARY, nullable);
252
24
            } else {
253
24
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_STRING, nullable);
254
24
            }
255
46
            break;
256
0
        case tparquet::Type::FIXED_LEN_BYTE_ARRAY:
257
0
            ans.first = DataTypeFactory::instance().create_data_type(TYPE_STRING, nullable);
258
0
            break;
259
0
        default:
260
0
            throw Exception(Status::InternalError("Not supported parquet logicalType{}",
261
0
                                                  physical_schema.type));
262
0
            break;
263
960
        }
264
960
    }
265
2.02k
    return ans;
266
2.02k
}
267
268
std::pair<DataTypePtr, bool> FieldDescriptor::convert_to_doris_type(
269
852
        tparquet::LogicalType logicalType, bool nullable) {
270
852
    std::pair<DataTypePtr, bool> ans = {std::make_shared<DataTypeNothing>(), false};
271
852
    bool& is_type_compatibility = ans.second;
272
852
    if (logicalType.__isset.GEOMETRY) {
273
2
        const std::string crs =
274
2
                logicalType.GEOMETRY.__isset.crs ? logicalType.GEOMETRY.crs : "OGC:CRS84";
275
        // OPTIONAL spatial fields must retain their definition-level threshold for COUNT.
276
2
        auto spatial_type = std::make_shared<DataTypeSpatial>(TYPE_GEOMETRY, crs);
277
2
        ans.first = nullable ? make_nullable(spatial_type) : spatial_type;
278
850
    } else if (logicalType.__isset.GEOGRAPHY) {
279
7
        const std::string crs =
280
7
                logicalType.GEOGRAPHY.__isset.crs ? logicalType.GEOGRAPHY.crs : "OGC:CRS84";
281
7
        const std::string algorithm = logicalType.GEOGRAPHY.__isset.algorithm
282
7
                                              ? tparquet::to_string(logicalType.GEOGRAPHY.algorithm)
283
7
                                              : "spherical";
284
        // OPTIONAL spatial fields must retain their definition-level threshold for COUNT.
285
7
        auto spatial_type = std::make_shared<DataTypeSpatial>(TYPE_GEOGRAPHY, crs, algorithm);
286
7
        ans.first = nullable ? make_nullable(spatial_type) : spatial_type;
287
843
    } else if (logicalType.__isset.STRING) {
288
502
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_STRING, nullable);
289
502
    } else if (logicalType.__isset.DECIMAL) {
290
162
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_DECIMAL128I, nullable,
291
162
                                                                 logicalType.DECIMAL.precision,
292
162
                                                                 logicalType.DECIMAL.scale);
293
179
    } else if (logicalType.__isset.DATE) {
294
81
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_DATEV2, nullable);
295
98
    } else if (logicalType.__isset.INTEGER) {
296
0
        if (logicalType.INTEGER.isSigned) {
297
0
            if (logicalType.INTEGER.bitWidth <= 8) {
298
0
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_TINYINT, nullable);
299
0
            } else if (logicalType.INTEGER.bitWidth <= 16) {
300
0
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_SMALLINT, nullable);
301
0
            } else if (logicalType.INTEGER.bitWidth <= 32) {
302
0
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_INT, nullable);
303
0
            } else {
304
0
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_BIGINT, nullable);
305
0
            }
306
0
        } else {
307
0
            is_type_compatibility = true;
308
0
            if (logicalType.INTEGER.bitWidth <= 8) {
309
0
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_SMALLINT, nullable);
310
0
            } else if (logicalType.INTEGER.bitWidth <= 16) {
311
0
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_INT, nullable);
312
0
            } else if (logicalType.INTEGER.bitWidth <= 32) {
313
0
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_BIGINT, nullable);
314
0
            } else {
315
0
                ans.first = DataTypeFactory::instance().create_data_type(TYPE_LARGEINT, nullable);
316
0
            }
317
0
        }
318
98
    } else if (logicalType.__isset.TIME) {
319
0
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_TIMEV2, nullable);
320
98
    } else if (logicalType.__isset.TIMESTAMP) {
321
93
        if (_enable_mapping_timestamp_tz) {
322
0
            if (logicalType.TIMESTAMP.isAdjustedToUTC) {
323
                // treat TIMESTAMP with isAdjustedToUTC as TIMESTAMPTZ
324
0
                ans.first = DataTypeFactory::instance().create_data_type(
325
0
                        TYPE_TIMESTAMPTZ, nullable, 0,
326
0
                        logicalType.TIMESTAMP.unit.__isset.MILLIS ? 3 : 6);
327
0
                return ans;
328
0
            }
329
0
        }
330
93
        ans.first = DataTypeFactory::instance().create_data_type(
331
93
                TYPE_DATETIMEV2, nullable, 0, logicalType.TIMESTAMP.unit.__isset.MILLIS ? 3 : 6);
332
93
    } else if (logicalType.__isset.JSON) {
333
0
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_STRING, nullable);
334
5
    } else if (logicalType.__isset.UUID) {
335
        // UUID is a logical type; its binary storage does not make it an untyped byte array.
336
5
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_UUID, nullable);
337
5
    } else if (logicalType.__isset.FLOAT16) {
338
0
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_FLOAT, nullable);
339
0
    } else {
340
0
        throw Exception(Status::InternalError("Not supported parquet logicalType"));
341
0
    }
342
852
    return ans;
343
852
}
344
345
std::pair<DataTypePtr, bool> FieldDescriptor::convert_to_doris_type(
346
226
        const tparquet::SchemaElement& physical_schema, bool nullable) {
347
226
    std::pair<DataTypePtr, bool> ans = {std::make_shared<DataTypeNothing>(), false};
348
226
    bool& is_type_compatibility = ans.second;
349
226
    switch (physical_schema.converted_type) {
350
106
    case tparquet::ConvertedType::type::UTF8:
351
106
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_STRING, nullable);
352
106
        break;
353
24
    case tparquet::ConvertedType::type::DECIMAL:
354
24
        ans.first = DataTypeFactory::instance().create_data_type(
355
24
                TYPE_DECIMAL128I, nullable, physical_schema.precision, physical_schema.scale);
356
24
        break;
357
24
    case tparquet::ConvertedType::type::DATE:
358
24
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_DATEV2, nullable);
359
24
        break;
360
0
    case tparquet::ConvertedType::type::TIME_MILLIS:
361
0
        [[fallthrough]];
362
0
    case tparquet::ConvertedType::type::TIME_MICROS:
363
0
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_TIMEV2, nullable);
364
0
        break;
365
0
    case tparquet::ConvertedType::type::TIMESTAMP_MILLIS:
366
0
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_DATETIMEV2, nullable, 0, 3);
367
0
        break;
368
24
    case tparquet::ConvertedType::type::TIMESTAMP_MICROS:
369
24
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_DATETIMEV2, nullable, 0, 6);
370
24
        break;
371
24
    case tparquet::ConvertedType::type::INT_8:
372
24
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_TINYINT, nullable);
373
24
        break;
374
0
    case tparquet::ConvertedType::type::UINT_8:
375
0
        is_type_compatibility = true;
376
0
        [[fallthrough]];
377
24
    case tparquet::ConvertedType::type::INT_16:
378
24
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_SMALLINT, nullable);
379
24
        break;
380
0
    case tparquet::ConvertedType::type::UINT_16:
381
0
        is_type_compatibility = true;
382
0
        [[fallthrough]];
383
0
    case tparquet::ConvertedType::type::INT_32:
384
0
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_INT, nullable);
385
0
        break;
386
0
    case tparquet::ConvertedType::type::UINT_32:
387
0
        is_type_compatibility = true;
388
0
        [[fallthrough]];
389
0
    case tparquet::ConvertedType::type::INT_64:
390
0
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_BIGINT, nullable);
391
0
        break;
392
0
    case tparquet::ConvertedType::type::UINT_64:
393
0
        is_type_compatibility = true;
394
0
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_LARGEINT, nullable);
395
0
        break;
396
0
    case tparquet::ConvertedType::type::JSON:
397
0
        ans.first = DataTypeFactory::instance().create_data_type(TYPE_STRING, nullable);
398
0
        break;
399
0
    default:
400
0
        throw Exception(Status::InternalError("Not supported parquet ConvertedType: {}",
401
0
                                              physical_schema.converted_type));
402
226
    }
403
226
    return ans;
404
226
}
405
406
Status FieldDescriptor::parse_group_field(const std::vector<tparquet::SchemaElement>& t_schemas,
407
533
                                          size_t curr_pos, FieldSchema* group_field) {
408
533
    auto& group_schema = t_schemas[curr_pos];
409
533
    if (is_map_node(group_schema)) {
410
        // the map definition:
411
        // optional group <name> (MAP) {
412
        //   repeated group map (MAP_KEY_VALUE) {
413
        //     required <type> key;
414
        //     optional <type> value;
415
        //   }
416
        // }
417
76
        return parse_map_field(t_schemas, curr_pos, group_field);
418
76
    }
419
457
    if (is_list_node(group_schema)) {
420
        // the list definition:
421
        // optional group <name> (LIST) {
422
        //   repeated group [bag | list] { // hive or spark
423
        //     optional <type> [array_element | element]; // hive or spark
424
        //   }
425
        // }
426
152
        return parse_list_field(t_schemas, curr_pos, group_field);
427
152
    }
428
429
305
    if (is_repeated_node(group_schema)) {
430
0
        group_field->repetition_level++;
431
0
        group_field->definition_level++;
432
0
        group_field->children.resize(1);
433
0
        set_child_node_level(group_field, group_field->definition_level);
434
0
        auto struct_field = &group_field->children[0];
435
        // the list of struct:
436
        // repeated group <name> (LIST) {
437
        //   optional/required <type> <name>;
438
        //   ...
439
        // }
440
        // produce a non-null list<struct>
441
0
        RETURN_IF_ERROR(parse_struct_field(t_schemas, curr_pos, struct_field));
442
443
0
        group_field->name = group_schema.name;
444
0
        group_field->lower_case_name = to_lower(group_field->name);
445
0
        group_field->column_id = UNASSIGNED_COLUMN_ID; // Initialize column_id
446
0
        group_field->data_type =
447
0
                std::make_shared<DataTypeArray>(make_nullable(struct_field->data_type));
448
0
        group_field->field_id = group_schema.__isset.field_id ? group_schema.field_id : -1;
449
305
    } else {
450
305
        RETURN_IF_ERROR(parse_struct_field(t_schemas, curr_pos, group_field));
451
305
    }
452
453
305
    return Status::OK();
454
305
}
455
456
Status FieldDescriptor::parse_list_field(const std::vector<tparquet::SchemaElement>& t_schemas,
457
152
                                         size_t curr_pos, FieldSchema* list_field) {
458
    // the list definition:
459
    // spark and hive have three level schemas but with different schema name
460
    // spark: <column-name> - "list" - "element"
461
    // hive: <column-name> - "bag" - "array_element"
462
    // parse three level schemas to two level primitive like: LIST<INT>,
463
    // or nested structure like: LIST<MAP<INT, INT>>
464
152
    auto& first_level = t_schemas[curr_pos];
465
152
    if (first_level.num_children != 1) {
466
0
        return Status::InvalidArgument("List element should have only one child");
467
0
    }
468
469
152
    if (curr_pos + 1 >= t_schemas.size()) {
470
0
        return Status::InvalidArgument("List element should have the second level schema");
471
0
    }
472
473
152
    if (first_level.repetition_type == tparquet::FieldRepetitionType::REPEATED) {
474
0
        return Status::InvalidArgument("List element can't be a repeated schema");
475
0
    }
476
477
    // the repeated schema element
478
152
    auto& second_level = t_schemas[curr_pos + 1];
479
152
    if (second_level.repetition_type != tparquet::FieldRepetitionType::REPEATED) {
480
0
        return Status::InvalidArgument("The second level of list element should be repeated");
481
0
    }
482
483
    // This indicates if this list is nullable.
484
152
    bool is_optional = is_optional_node(first_level);
485
152
    if (is_optional) {
486
116
        list_field->definition_level++;
487
116
    }
488
152
    list_field->repetition_level++;
489
152
    list_field->definition_level++;
490
152
    list_field->children.resize(1);
491
152
    FieldSchema* list_child = &list_field->children[0];
492
493
152
    size_t num_children = num_children_node(second_level);
494
152
    if (num_children > 0) {
495
152
        if (num_children == 1 && !is_struct_list_node(second_level)) {
496
            // optional field, and the third level element is the nested structure in list
497
            // produce nested structure like: LIST<INT>, LIST<MAP>, LIST<LIST<...>>
498
            // skip bag/list, it's a repeated element.
499
152
            set_child_node_level(list_field, list_field->definition_level);
500
152
            RETURN_IF_ERROR(parse_node_field(t_schemas, curr_pos + 2, list_child));
501
152
        } else {
502
            // required field, produce the list of struct
503
0
            set_child_node_level(list_field, list_field->definition_level);
504
0
            RETURN_IF_ERROR(parse_struct_field(t_schemas, curr_pos + 1, list_child));
505
0
        }
506
152
    } else if (num_children == 0) {
507
        // required two level list, for compatibility reason.
508
0
        set_child_node_level(list_field, list_field->definition_level);
509
0
        parse_physical_field(second_level, false, list_child);
510
0
        _next_schema_pos = curr_pos + 2;
511
0
    }
512
513
152
    list_field->name = first_level.name;
514
152
    list_field->lower_case_name = to_lower(first_level.name);
515
152
    list_field->column_id = UNASSIGNED_COLUMN_ID; // Initialize column_id
516
152
    list_field->data_type =
517
152
            std::make_shared<DataTypeArray>(make_nullable(list_field->children[0].data_type));
518
152
    if (is_optional) {
519
116
        list_field->data_type = make_nullable(list_field->data_type);
520
116
    }
521
152
    list_field->field_id = first_level.__isset.field_id ? first_level.field_id : -1;
522
523
152
    return Status::OK();
524
152
}
525
526
Status FieldDescriptor::parse_map_field(const std::vector<tparquet::SchemaElement>& t_schemas,
527
76
                                        size_t curr_pos, FieldSchema* map_field) {
528
    // the map definition in parquet:
529
    // optional group <name> (MAP) {
530
    //   repeated group map (MAP_KEY_VALUE) {
531
    //     required <type> key;
532
    //     optional <type> value;
533
    //   }
534
    // }
535
    // Map value can be optional, the map without values is a SET
536
76
    if (curr_pos + 2 >= t_schemas.size()) {
537
0
        return Status::InvalidArgument("Map element should have at least three levels");
538
0
    }
539
76
    auto& map_schema = t_schemas[curr_pos];
540
76
    if (map_schema.num_children != 1) {
541
0
        return Status::InvalidArgument(
542
0
                "Map element should have only one child(name='map', type='MAP_KEY_VALUE')");
543
0
    }
544
76
    if (is_repeated_node(map_schema)) {
545
0
        return Status::InvalidArgument("Map element can't be a repeated schema");
546
0
    }
547
76
    auto& map_key_value = t_schemas[curr_pos + 1];
548
76
    if (!is_group_node(map_key_value) || !is_repeated_node(map_key_value)) {
549
0
        return Status::InvalidArgument(
550
0
                "the second level in map must be a repeated group(key and value)");
551
0
    }
552
76
    auto& map_key = t_schemas[curr_pos + 2];
553
76
    if (!is_required_node(map_key)) {
554
0
        LOG(WARNING) << "Filed " << map_schema.name << " is map type, but with nullable key column";
555
0
    }
556
557
76
    if (map_key_value.num_children == 1) {
558
        // The map with three levels is a SET
559
0
        return parse_list_field(t_schemas, curr_pos, map_field);
560
0
    }
561
76
    if (map_key_value.num_children != 2) {
562
        // A standard map should have four levels
563
0
        return Status::InvalidArgument(
564
0
                "the second level in map(MAP_KEY_VALUE) should have two children");
565
0
    }
566
    // standard map
567
76
    bool is_optional = is_optional_node(map_schema);
568
76
    if (is_optional) {
569
52
        map_field->definition_level++;
570
52
    }
571
76
    map_field->repetition_level++;
572
76
    map_field->definition_level++;
573
574
    // Directly create key and value children instead of intermediate key_value node
575
76
    map_field->children.resize(2);
576
    // map is a repeated node, we should set the `repeated_parent_def_level` of its children as `definition_level`
577
76
    set_child_node_level(map_field, map_field->definition_level);
578
579
76
    auto key_field = &map_field->children[0];
580
76
    auto value_field = &map_field->children[1];
581
582
    // Parse key and value fields directly from the key_value group's children
583
76
    _next_schema_pos = curr_pos + 2; // Skip key_value group, go directly to key
584
76
    RETURN_IF_ERROR(parse_node_field(t_schemas, _next_schema_pos, key_field));
585
76
    RETURN_IF_ERROR(parse_node_field(t_schemas, _next_schema_pos, value_field));
586
587
76
    map_field->name = map_schema.name;
588
76
    map_field->lower_case_name = to_lower(map_field->name);
589
76
    map_field->column_id = UNASSIGNED_COLUMN_ID; // Initialize column_id
590
76
    map_field->data_type = std::make_shared<DataTypeMap>(make_nullable(key_field->data_type),
591
76
                                                         make_nullable(value_field->data_type));
592
76
    if (is_optional) {
593
52
        map_field->data_type = make_nullable(map_field->data_type);
594
52
    }
595
76
    map_field->field_id = map_schema.__isset.field_id ? map_schema.field_id : -1;
596
597
76
    return Status::OK();
598
76
}
599
600
Status FieldDescriptor::parse_struct_field(const std::vector<tparquet::SchemaElement>& t_schemas,
601
305
                                           size_t curr_pos, FieldSchema* struct_field) {
602
    // the nested column in parquet, parse group to struct.
603
305
    auto& struct_schema = t_schemas[curr_pos];
604
305
    bool is_optional = is_optional_node(struct_schema);
605
305
    if (is_optional) {
606
288
        struct_field->definition_level++;
607
288
    }
608
305
    auto num_children = struct_schema.num_children;
609
305
    struct_field->children.resize(num_children);
610
305
    set_child_node_level(struct_field, struct_field->repeated_parent_def_level);
611
305
    _next_schema_pos = curr_pos + 1;
612
1.09k
    for (int i = 0; i < num_children; ++i) {
613
792
        RETURN_IF_ERROR(parse_node_field(t_schemas, _next_schema_pos, &struct_field->children[i]));
614
792
    }
615
305
    struct_field->name = struct_schema.name;
616
305
    struct_field->lower_case_name = to_lower(struct_field->name);
617
305
    struct_field->column_id = UNASSIGNED_COLUMN_ID; // Initialize column_id
618
619
305
    struct_field->field_id = struct_schema.__isset.field_id ? struct_schema.field_id : -1;
620
305
    DataTypes res_data_types;
621
305
    std::vector<String> names;
622
1.09k
    for (int i = 0; i < num_children; ++i) {
623
792
        res_data_types.push_back(make_nullable(struct_field->children[i].data_type));
624
792
        names.push_back(struct_field->children[i].name);
625
792
    }
626
305
    struct_field->data_type = std::make_shared<DataTypeStruct>(res_data_types, names);
627
305
    if (is_optional) {
628
288
        struct_field->data_type = make_nullable(struct_field->data_type);
629
288
    }
630
305
    return Status::OK();
631
305
}
632
633
5
int FieldDescriptor::get_column_index(const std::string& column) const {
634
15
    for (int32_t i = 0; i < _fields.size(); i++) {
635
15
        if (_fields[i].name == column) {
636
5
            return i;
637
5
        }
638
15
    }
639
0
    return -1;
640
5
}
641
642
1.36k
FieldSchema* FieldDescriptor::get_column(const std::string& name) const {
643
1.36k
    auto it = _name_to_field.find(name);
644
1.36k
    if (it != _name_to_field.end()) {
645
1.36k
        return it->second;
646
1.36k
    }
647
0
    throw Exception(Status::InternalError("Name {} not found in FieldDescriptor!", name));
648
0
    return nullptr;
649
1.36k
}
650
651
14
void FieldDescriptor::get_column_names(std::unordered_set<std::string>* names) const {
652
14
    names->clear();
653
210
    for (const FieldSchema& f : _fields) {
654
210
        names->emplace(f.name);
655
210
    }
656
14
}
657
658
0
std::string FieldDescriptor::debug_string() const {
659
0
    std::stringstream ss;
660
0
    ss << "fields=[";
661
0
    for (int i = 0; i < _fields.size(); ++i) {
662
0
        if (i != 0) {
663
0
            ss << ", ";
664
0
        }
665
0
        ss << _fields[i].debug_string();
666
0
    }
667
0
    ss << "]";
668
0
    return ss.str();
669
0
}
670
671
51
void FieldDescriptor::assign_ids() {
672
51
    uint64_t next_id = 1;
673
398
    for (auto& field : _fields) {
674
398
        field.assign_ids(next_id);
675
398
    }
676
51
}
677
678
0
const FieldSchema* FieldDescriptor::find_column_by_id(uint64_t column_id) const {
679
0
    for (const auto& field : _fields) {
680
0
        if (auto result = field.find_column_by_id(column_id)) {
681
0
            return result;
682
0
        }
683
0
    }
684
0
    return nullptr;
685
0
}
686
687
1.95k
void FieldSchema::assign_ids(uint64_t& next_id) {
688
1.95k
    column_id = next_id++;
689
690
1.95k
    for (auto& child : children) {
691
1.55k
        child.assign_ids(next_id);
692
1.55k
    }
693
694
1.95k
    max_column_id = next_id - 1;
695
1.95k
}
696
697
0
const FieldSchema* FieldSchema::find_column_by_id(uint64_t target_id) const {
698
0
    if (column_id == target_id) {
699
0
        return this;
700
0
    }
701
702
0
    for (const auto& child : children) {
703
0
        if (auto result = child.find_column_by_id(target_id)) {
704
0
            return result;
705
0
        }
706
0
    }
707
708
0
    return nullptr;
709
0
}
710
711
399
uint64_t FieldSchema::get_column_id() const {
712
399
    return column_id;
713
399
}
714
715
0
void FieldSchema::set_column_id(uint64_t id) {
716
0
    column_id = id;
717
0
}
718
719
121
uint64_t FieldSchema::get_max_column_id() const {
720
121
    return max_column_id;
721
121
}
722
723
} // namespace doris