Coverage Report

Created: 2026-10-29 12:42

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