Coverage Report

Created: 2026-10-30 17:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/function/cast/cast_to_map.h
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 <array>
19
20
#include "core/column/column_map.h"
21
#include "core/column/column_nullable.h"
22
#include "core/data_type/data_type_map.h"
23
#include "exprs/function/cast/cast_base.h"
24
25
namespace doris::CastWrapper {
26
//TODO(Amory) . Need support more cast for key , value for map
27
WrapperType create_map_wrapper(const CastOptions& options, const DataTypePtr& from_type,
28
16
                               const DataTypeMap& to_type) {
29
16
    if (is_string_type(from_type->get_primitive_type())) {
30
9
        return options.strict_mode ? cast_from_string_to_complex_type_strict_mode
31
9
                                   : cast_from_string_to_complex_type;
32
9
    }
33
7
    const auto* from = check_and_get_data_type<DataTypeMap>(from_type.get());
34
7
    if (!from) {
35
0
        return CastWrapper::create_unsupport_wrapper(
36
0
                fmt::format("CAST AS Map can only be performed between Map types or from "
37
0
                            "String. from type: {}, to type: {}",
38
0
                            from_type->get_name(), to_type.get_name()));
39
0
    }
40
7
    DataTypes from_kv_types;
41
7
    DataTypes to_kv_types;
42
7
    from_kv_types.reserve(2);
43
7
    to_kv_types.reserve(2);
44
7
    from_kv_types.push_back(from->get_key_type());
45
7
    from_kv_types.push_back(from->get_value_type());
46
7
    to_kv_types.push_back(to_type.get_key_type());
47
7
    to_kv_types.push_back(to_type.get_value_type());
48
49
7
    auto kv_wrappers = get_element_wrappers(options, from_kv_types, to_kv_types);
50
    /// A key or value whose type does not change is passed through, so it needs neither a child mask
51
    /// nor a call into its (identity) wrapper.
52
7
    std::array<bool, 2> unchanged_kv = {from_kv_types[0]->equals(*to_kv_types[0]),
53
7
                                        from_kv_types[1]->equals(*to_kv_types[1])};
54
7
    return [kv_wrappers, from_kv_types, to_kv_types, unchanged_kv](
55
7
                   RuntimeState* state, const ColumnWithTypeAndName& source_column,
56
7
                   ColumnWithTypeAndName& target_column, size_t /*input_rows_count*/,
57
16
                   const NullMap::value_type* parent_null_map = nullptr) -> Status {
58
16
        const auto* from_col_map = check_and_get_column<ColumnMap>(source_column.column.get());
59
16
        if (!from_col_map) {
60
0
            return Status::RuntimeError("Illegal column {} for function CAST AS MAP",
61
0
                                        source_column.column->get_name());
62
0
        }
63
64
16
        Columns converted_columns(2);
65
16
        ColumnsWithTypeAndName columnsWithTypeAndName(2);
66
16
        columnsWithTypeAndName[0] = {from_col_map->get_keys_ptr(), from_kv_types[0], ""};
67
16
        columnsWithTypeAndName[1] = {from_col_map->get_values_ptr(), from_kv_types[1], ""};
68
69
16
        const auto& offsets = from_col_map->get_offsets();
70
        // Keys and values share the rows of their parent, so the parent mask is scanned once.
71
16
        const NullMap::value_type* effective_parent_null_map =
72
16
                (parent_null_map != nullptr && has_masked_row(parent_null_map, offsets.size()))
73
16
                        ? parent_null_map
74
16
                        : nullptr;
75
42
        for (size_t i = 0; i < 2; ++i) {
76
31
            if (unchanged_kv[i]) {
77
14
                converted_columns[i] = columnsWithTypeAndName[i].column;
78
14
                continue;
79
14
            }
80
            /// Keys and values are flattened, so the NULL of a map row has to be inherited by the
81
            /// entries that belong to it before they are cast.
82
17
            auto child_mask = build_child_null_mask(effective_parent_null_map, &offsets,
83
17
                                                    columnsWithTypeAndName[i].column);
84
17
            ColumnWithTypeAndName child_column {child_mask.column, from_kv_types[i], ""};
85
17
            ColumnWithTypeAndName element_result {nullptr, to_kv_types[i], ""};
86
17
            RETURN_IF_ERROR(kv_wrappers[i](state, child_column, element_result,
87
17
                                           child_mask.column->size(), child_mask.null_map));
88
12
            converted_columns[i] = std::move(element_result.column);
89
12
        }
90
91
11
        auto map_column = ColumnMap::create(converted_columns[0], converted_columns[1],
92
11
                                            from_col_map->get_offsets_ptr());
93
11
        static_cast<void>(map_column->deduplicate_keys());
94
11
        target_column.column = std::move(map_column);
95
11
        return Status::OK();
96
16
    };
97
7
}
98
} // namespace doris::CastWrapper