Coverage Report

Created: 2026-10-12 18:55

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(FunctionContext* context, const DataTypePtr& from_type,
28
25
                               const DataTypeMap& to_type) {
29
25
    if (is_string_type(from_type->get_primitive_type())) {
30
9
        if (context->enable_strict_mode()) {
31
3
            return cast_from_string_to_complex_type_strict_mode;
32
6
        } else {
33
6
            return cast_from_string_to_complex_type;
34
6
        }
35
9
    }
36
16
    const auto* from = check_and_get_data_type<DataTypeMap>(from_type.get());
37
16
    if (!from) {
38
0
        return CastWrapper::create_unsupport_wrapper(
39
0
                fmt::format("CAST AS Map can only be performed between Map types or from "
40
0
                            "String. from type: {}, to type: {}",
41
0
                            from_type->get_name(), to_type.get_name()));
42
0
    }
43
16
    DataTypes from_kv_types;
44
16
    DataTypes to_kv_types;
45
16
    from_kv_types.reserve(2);
46
16
    to_kv_types.reserve(2);
47
16
    from_kv_types.push_back(from->get_key_type());
48
16
    from_kv_types.push_back(from->get_value_type());
49
16
    to_kv_types.push_back(to_type.get_key_type());
50
16
    to_kv_types.push_back(to_type.get_value_type());
51
52
16
    auto kv_wrappers = get_element_wrappers(context, from_kv_types, to_kv_types);
53
    /// A key or value whose type does not change is passed through, so it needs neither a child mask
54
    /// nor a call into its (identity) wrapper.
55
16
    std::array<bool, 2> unchanged_kv = {from_kv_types[0]->equals(*to_kv_types[0]),
56
16
                                        from_kv_types[1]->equals(*to_kv_types[1])};
57
16
    return [kv_wrappers, from_kv_types, to_kv_types, unchanged_kv](
58
16
                   FunctionContext* context, Block& block, const ColumnNumbers& arguments,
59
16
                   uint32_t result, size_t /*input_rows_count*/,
60
16
                   const NullMap::value_type* null_map = nullptr) -> Status {
61
16
        auto& from_column = block.get_by_position(arguments.front()).column;
62
16
        const auto* from_col_map = check_and_get_column<ColumnMap>(from_column.get());
63
16
        if (!from_col_map) {
64
0
            return Status::RuntimeError("Illegal column {} for function CAST AS MAP",
65
0
                                        from_column->get_name());
66
0
        }
67
68
16
        Columns converted_columns(2);
69
16
        ColumnsWithTypeAndName columnsWithTypeAndName(2);
70
16
        columnsWithTypeAndName[0] = {from_col_map->get_keys_ptr(), from_kv_types[0], ""};
71
16
        columnsWithTypeAndName[1] = {from_col_map->get_values_ptr(), from_kv_types[1], ""};
72
73
16
        const auto& offsets = from_col_map->get_offsets();
74
        // Keys and values share the rows of their parent, so the parent mask is scanned once.
75
16
        const NullMap::value_type* inherited_null_map =
76
16
                (null_map != nullptr && has_masked_row(null_map, offsets.size())) ? null_map
77
16
                                                                                  : nullptr;
78
42
        for (size_t i = 0; i < 2; ++i) {
79
31
            if (unchanged_kv[i]) {
80
14
                converted_columns[i] = columnsWithTypeAndName[i].column;
81
14
                continue;
82
14
            }
83
            /// Keys and values are flattened, so the NULL of a map row has to be inherited by the
84
            /// entries that belong to it before they are cast.
85
17
            auto child_mask = build_child_null_mask(inherited_null_map, &offsets,
86
17
                                                    columnsWithTypeAndName[i].column);
87
17
            ColumnWithTypeAndName child_column {child_mask.column, from_kv_types[i], ""};
88
17
            ColumnNumbers element_arguments {block.columns()};
89
17
            block.insert(child_column);
90
17
            auto element_result = block.columns();
91
17
            block.insert({to_kv_types[i], ""});
92
17
            RETURN_IF_ERROR(kv_wrappers[i](context, block, element_arguments, element_result,
93
17
                                           child_mask.column->size(), child_mask.null_map));
94
12
            converted_columns[i] = block.get_by_position(element_result).column;
95
12
        }
96
97
11
        auto map_column = ColumnMap::create(converted_columns[0], converted_columns[1],
98
11
                                            from_col_map->get_offsets_ptr());
99
11
        static_cast<void>(map_column->deduplicate_keys());
100
11
        block.get_by_position(result).column = std::move(map_column);
101
11
        return Status::OK();
102
16
    };
103
16
}
104
} // namespace doris::CastWrapper