xiaokang commented on code in PR #15966:
URL: https://github.com/apache/doris/pull/15966#discussion_r1072094803


##########
be/src/vec/data_types/data_type_factory.cpp:
##########
@@ -94,8 +101,8 @@ DataTypePtr DataTypeFactory::create_data_type(const 
TypeDescriptor& col_desc, bo
         break;
     case TYPE_TIME:
     case TYPE_TIMEV2:
-        nested = std::make_shared<vectorized::DataTypeTime>();
-        break;
+       nested = std::make_shared<vectorized::DataTypeTime>();

Review Comment:
   mistake



##########
be/src/vec/columns/column_map.cpp:
##########
@@ -0,0 +1,218 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+// This file is copied from
+// 
https://github.com/ClickHouse/ClickHouse/blob/master/src/Columns/ColumnMap.cpp
+// and modified by Doris
+
+#include "vec/columns/column_map.h"
+
+namespace doris::vectorized {
+
+/** A column of map values.
+  */
+std::string ColumnMap::get_name() const {
+    return "Map(" + keys->get_name() + ", " + values->get_name() + ")";
+}
+
+ColumnMap::ColumnMap(MutableColumnPtr&& keys, MutableColumnPtr&& values)
+        : keys(std::move(keys)), values(std::move(values)) {
+    check_size();
+}
+
+ColumnArray::Offsets64& ColumnMap::get_offsets() const {
+    const ColumnArray & column_keys = assert_cast<const ColumnArray &> 
(get_keys());
+    // todo . did here check size ?
+    return const_cast<Offsets64&>(column_keys.get_offsets());
+}
+
+void ColumnMap::check_size() const {
+    const auto * key_array = typeid_cast<const ColumnArray *>(keys.get());
+    const auto * value_array = typeid_cast<const ColumnArray *>(values.get());
+    CHECK(key_array) << "ColumnMap keys can be created only from array";
+    CHECK(value_array) << "ColumnMap values can be created only from array";
+    CHECK_EQ(get_keys_ptr()->size(), get_values_ptr()->size());
+}
+
+// todo. here to resize every row map
+MutableColumnPtr ColumnMap::clone_resized(size_t to_size) const {
+    auto res = ColumnMap::create(keys->clone_resized(to_size), 
values->clone_resized(to_size));
+    return res;
+}
+
+// to support field functions
+Field ColumnMap::operator[](size_t n) const {
+    Map res(2);
+    keys->get(n, res[0]);
+    values->get(n, res[0]);
+
+    return res;
+}
+
+// here to compare to below
+void ColumnMap::get(size_t n, Field & res) const {
+    Map map(2);
+    keys->get(n, map[0]);
+    values->get(n, map[1]);
+
+    res = map;
+}
+
+StringRef ColumnMap::get_data_at(size_t n) const {
+    LOG(FATAL) << "Method get_data_at is not supported for " << get_name();
+}
+
+void ColumnMap::insert_data(const char*, size_t) {
+    LOG(FATAL) << "Method insert_data is not supported for " << get_name();
+}
+
+void ColumnMap::insert(const Field& x) {
+    const auto& map = doris::vectorized::get<const Map&>(x);
+    // ({}, {}, {})

Review Comment:
   confusing comment



##########
be/src/vec/data_types/data_type_factory.hpp:
##########
@@ -33,10 +33,12 @@
 #include "vec/data_types/data_type_bitmap.h"
 #include "vec/data_types/data_type_date.h"
 #include "vec/data_types/data_type_date_time.h"
+#include "vec/data_types/data_type_date_time.h"
 #include "vec/data_types/data_type_decimal.h"
 #include "vec/data_types/data_type_fixed_length_object.h"
 #include "vec/data_types/data_type_hll.h"
 #include "vec/data_types/data_type_jsonb.h"
+#include "vec/data_types/data_type_map.h"

Review Comment:
   not used. should process map like array.



##########
be/src/vec/columns/column_map.cpp:
##########
@@ -0,0 +1,218 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+// This file is copied from
+// 
https://github.com/ClickHouse/ClickHouse/blob/master/src/Columns/ColumnMap.cpp
+// and modified by Doris
+
+#include "vec/columns/column_map.h"
+
+namespace doris::vectorized {
+
+/** A column of map values.
+  */
+std::string ColumnMap::get_name() const {
+    return "Map(" + keys->get_name() + ", " + values->get_name() + ")";
+}
+
+ColumnMap::ColumnMap(MutableColumnPtr&& keys, MutableColumnPtr&& values)
+        : keys(std::move(keys)), values(std::move(values)) {
+    check_size();
+}
+
+ColumnArray::Offsets64& ColumnMap::get_offsets() const {
+    const ColumnArray & column_keys = assert_cast<const ColumnArray &> 
(get_keys());
+    // todo . did here check size ?
+    return const_cast<Offsets64&>(column_keys.get_offsets());
+}
+
+void ColumnMap::check_size() const {
+    const auto * key_array = typeid_cast<const ColumnArray *>(keys.get());
+    const auto * value_array = typeid_cast<const ColumnArray *>(values.get());
+    CHECK(key_array) << "ColumnMap keys can be created only from array";
+    CHECK(value_array) << "ColumnMap values can be created only from array";
+    CHECK_EQ(get_keys_ptr()->size(), get_values_ptr()->size());
+}
+
+// todo. here to resize every row map
+MutableColumnPtr ColumnMap::clone_resized(size_t to_size) const {
+    auto res = ColumnMap::create(keys->clone_resized(to_size), 
values->clone_resized(to_size));
+    return res;
+}
+
+// to support field functions
+Field ColumnMap::operator[](size_t n) const {
+    Map res(2);
+    keys->get(n, res[0]);
+    values->get(n, res[0]);

Review Comment:
   res[1]



##########
be/src/vec/columns/column_map.cpp:
##########
@@ -0,0 +1,218 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+// This file is copied from
+// 
https://github.com/ClickHouse/ClickHouse/blob/master/src/Columns/ColumnMap.cpp
+// and modified by Doris
+
+#include "vec/columns/column_map.h"
+
+namespace doris::vectorized {
+
+/** A column of map values.
+  */
+std::string ColumnMap::get_name() const {
+    return "Map(" + keys->get_name() + ", " + values->get_name() + ")";
+}
+
+ColumnMap::ColumnMap(MutableColumnPtr&& keys, MutableColumnPtr&& values)
+        : keys(std::move(keys)), values(std::move(values)) {
+    check_size();
+}
+
+ColumnArray::Offsets64& ColumnMap::get_offsets() const {
+    const ColumnArray & column_keys = assert_cast<const ColumnArray &> 
(get_keys());
+    // todo . did here check size ?
+    return const_cast<Offsets64&>(column_keys.get_offsets());
+}
+
+void ColumnMap::check_size() const {
+    const auto * key_array = typeid_cast<const ColumnArray *>(keys.get());
+    const auto * value_array = typeid_cast<const ColumnArray *>(values.get());
+    CHECK(key_array) << "ColumnMap keys can be created only from array";
+    CHECK(value_array) << "ColumnMap values can be created only from array";
+    CHECK_EQ(get_keys_ptr()->size(), get_values_ptr()->size());
+}
+
+// todo. here to resize every row map
+MutableColumnPtr ColumnMap::clone_resized(size_t to_size) const {
+    auto res = ColumnMap::create(keys->clone_resized(to_size), 
values->clone_resized(to_size));
+    return res;
+}
+
+// to support field functions
+Field ColumnMap::operator[](size_t n) const {
+    Map res(2);
+    keys->get(n, res[0]);
+    values->get(n, res[0]);
+
+    return res;
+}
+
+// here to compare to below
+void ColumnMap::get(size_t n, Field & res) const {
+    Map map(2);
+    keys->get(n, map[0]);
+    values->get(n, map[1]);
+
+    res = map;
+}
+
+StringRef ColumnMap::get_data_at(size_t n) const {
+    LOG(FATAL) << "Method get_data_at is not supported for " << get_name();
+}
+
+void ColumnMap::insert_data(const char*, size_t) {
+    LOG(FATAL) << "Method insert_data is not supported for " << get_name();
+}
+
+void ColumnMap::insert(const Field& x) {
+    const auto& map = doris::vectorized::get<const Map&>(x);
+    // ({}, {}, {})
+    // ([], [])
+    CHECK_EQ(map.size(), 2);
+    keys->insert(map[0]);
+    values->insert(map[1]);
+}
+
+void ColumnMap::insert_default() {

Review Comment:
   map default should be empty, so do not need to call 
keys/values->insert_default()



##########
be/src/vec/columns/column_map.cpp:
##########
@@ -0,0 +1,218 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+// This file is copied from
+// 
https://github.com/ClickHouse/ClickHouse/blob/master/src/Columns/ColumnMap.cpp
+// and modified by Doris
+
+#include "vec/columns/column_map.h"
+
+namespace doris::vectorized {
+
+/** A column of map values.
+  */
+std::string ColumnMap::get_name() const {
+    return "Map(" + keys->get_name() + ", " + values->get_name() + ")";
+}
+
+ColumnMap::ColumnMap(MutableColumnPtr&& keys, MutableColumnPtr&& values)
+        : keys(std::move(keys)), values(std::move(values)) {
+    check_size();
+}
+
+ColumnArray::Offsets64& ColumnMap::get_offsets() const {
+    const ColumnArray & column_keys = assert_cast<const ColumnArray &> 
(get_keys());
+    // todo . did here check size ?
+    return const_cast<Offsets64&>(column_keys.get_offsets());
+}
+
+void ColumnMap::check_size() const {
+    const auto * key_array = typeid_cast<const ColumnArray *>(keys.get());
+    const auto * value_array = typeid_cast<const ColumnArray *>(values.get());
+    CHECK(key_array) << "ColumnMap keys can be created only from array";
+    CHECK(value_array) << "ColumnMap values can be created only from array";
+    CHECK_EQ(get_keys_ptr()->size(), get_values_ptr()->size());
+}
+
+// todo. here to resize every row map
+MutableColumnPtr ColumnMap::clone_resized(size_t to_size) const {
+    auto res = ColumnMap::create(keys->clone_resized(to_size), 
values->clone_resized(to_size));
+    return res;
+}
+
+// to support field functions
+Field ColumnMap::operator[](size_t n) const {
+    Map res(2);

Review Comment:
   add comment for type Map



##########
be/src/runtime/types.cpp:
##########
@@ -131,7 +132,7 @@ void TypeDescriptor::to_thrift(TTypeDesc* thrift_type) 
const {
 }
 
 void TypeDescriptor::to_protobuf(PTypeDesc* ptype) const {
-    DCHECK(!is_complex_type() || type == TYPE_ARRAY)
+    DCHECK(!is_complex_type() || type == TYPE_ARRAY || type == TYPE_MAP)

Review Comment:
   it's strange and may be a lagacy check



##########
be/src/vec/columns/column_map.cpp:
##########
@@ -0,0 +1,218 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+// This file is copied from
+// 
https://github.com/ClickHouse/ClickHouse/blob/master/src/Columns/ColumnMap.cpp
+// and modified by Doris
+
+#include "vec/columns/column_map.h"
+
+namespace doris::vectorized {
+
+/** A column of map values.
+  */
+std::string ColumnMap::get_name() const {
+    return "Map(" + keys->get_name() + ", " + values->get_name() + ")";
+}
+
+ColumnMap::ColumnMap(MutableColumnPtr&& keys, MutableColumnPtr&& values)
+        : keys(std::move(keys)), values(std::move(values)) {
+    check_size();
+}
+
+ColumnArray::Offsets64& ColumnMap::get_offsets() const {
+    const ColumnArray & column_keys = assert_cast<const ColumnArray &> 
(get_keys());
+    // todo . did here check size ?
+    return const_cast<Offsets64&>(column_keys.get_offsets());
+}
+
+void ColumnMap::check_size() const {
+    const auto * key_array = typeid_cast<const ColumnArray *>(keys.get());
+    const auto * value_array = typeid_cast<const ColumnArray *>(values.get());
+    CHECK(key_array) << "ColumnMap keys can be created only from array";
+    CHECK(value_array) << "ColumnMap values can be created only from array";
+    CHECK_EQ(get_keys_ptr()->size(), get_values_ptr()->size());
+}
+
+// todo. here to resize every row map
+MutableColumnPtr ColumnMap::clone_resized(size_t to_size) const {
+    auto res = ColumnMap::create(keys->clone_resized(to_size), 
values->clone_resized(to_size));
+    return res;
+}
+
+// to support field functions
+Field ColumnMap::operator[](size_t n) const {
+    Map res(2);
+    keys->get(n, res[0]);
+    values->get(n, res[0]);
+
+    return res;
+}
+
+// here to compare to below
+void ColumnMap::get(size_t n, Field & res) const {
+    Map map(2);
+    keys->get(n, map[0]);
+    values->get(n, map[1]);
+
+    res = map;
+}
+
+StringRef ColumnMap::get_data_at(size_t n) const {
+    LOG(FATAL) << "Method get_data_at is not supported for " << get_name();
+}
+
+void ColumnMap::insert_data(const char*, size_t) {
+    LOG(FATAL) << "Method insert_data is not supported for " << get_name();
+}
+
+void ColumnMap::insert(const Field& x) {
+    const auto& map = doris::vectorized::get<const Map&>(x);
+    // ({}, {}, {})
+    // ([], [])
+    CHECK_EQ(map.size(), 2);
+    keys->insert(map[0]);
+    values->insert(map[1]);
+}
+
+void ColumnMap::insert_default() {
+    keys->insert_default();
+    values->insert_default();
+}
+
+void ColumnMap::pop_back(size_t n) {
+    keys->pop_back(n);
+    values->pop_back(n);
+}
+
+StringRef ColumnMap::serialize_value_into_arena(size_t n, Arena & arena, char 
const*& begin)
+        const {
+    StringRef res(begin, 0);
+    auto keys_ref = keys->serialize_value_into_arena(n, arena, begin);
+    res.data = keys_ref.data - res.size;
+    res.size += keys_ref.size;
+    auto value_ref = values->serialize_value_into_arena(n, arena, begin);
+    res.data = value_ref.data - res.size;
+    res.size += value_ref.size;
+
+    return res;
+}
+
+void ColumnMap::insert_from(const IColumn& src_, size_t n) {
+    const ColumnMap& src = assert_cast<const ColumnMap&>(src_);
+
+    if ((!get_keys().is_nullable() && src.get_keys().is_nullable())
+        || (!get_values().is_nullable() && src.get_values().is_nullable())) {
+        DCHECK(false);
+    } else if ((get_keys().is_nullable() && !src.get_keys().is_nullable())
+               || (get_values().is_nullable() && 
!src.get_values().is_nullable())) {
+        DCHECK(false);
+    } else {
+        keys->insert_from(*assert_cast<const ColumnMap&>(src_).keys, n);
+        values->insert_from(*assert_cast<const ColumnMap&>(src_).values, n);
+    }
+}
+
+void ColumnMap::insert_indices_from(const IColumn& src, const int* 
indices_begin,
+                                      const int* indices_end) {
+    for (auto x = indices_begin; x != indices_end; ++x) {
+        if (*x == -1) {
+            ColumnMap::insert_default();
+        } else {
+            ColumnMap::insert_from(src, *x);
+        }
+    }
+}
+
+const char* ColumnMap::deserialize_and_insert_from_arena(const char* pos) {
+    pos = keys->deserialize_and_insert_from_arena(pos);
+    pos = values->deserialize_and_insert_from_arena(pos);
+
+    return pos;
+}
+
+void ColumnMap::update_hash_with_value(size_t n, SipHash & hash) const {
+    keys->update_hash_with_value(n, hash);
+    values->update_hash_with_value(n, hash);
+}
+
+void ColumnMap::insert_range_from(const IColumn& src, size_t start, size_t 
length) {
+    keys->insert_range_from(*assert_cast<const ColumnMap&>(src).keys, start, 
length);
+    values->insert_range_from(*assert_cast<const ColumnMap&>(src).values, 
start, length);
+}
+
+ColumnPtr ColumnMap::filter(const Filter& filt, ssize_t result_size_hint) 
const {
+    return ColumnMap::create(keys->filter(filt, result_size_hint), 
values->filter(filt, result_size_hint));
+}
+
+ColumnPtr ColumnMap::permute(const Permutation& perm, size_t limit) const {
+    return ColumnMap::create(keys->permute(perm, limit), values->permute(perm, 
limit));
+}
+
+ColumnPtr ColumnMap::replicate(const Offsets& offsets) const {
+    return ColumnMap::create(keys->replicate(offsets), 
values->replicate(offsets));
+}
+
+//MutableColumns ColumnMap::scatter(ColumnIndex num_columns, const Selector& 
selector) const {
+//
+//    MutableColumns keys_scatter = keys->scatter(num_columns, selector);
+//    MutableColumns values_scatter = values->scatter(num_columns, selector);
+//
+//    MutableColumns res(num_columns);
+//
+//    for (size_t scattered_idx = 0; scattered_idx < num_columns; 
++scattered_idx)
+//    {
+//        MutableColumns new_columns(2);
+//        for (size_t map_element_idx = 0; map_element_idx < 2; 
++map_element_idx)
+//            new_columns[map_element_idx] = 
std::move(scattered_map_elements[map_element_idx][scattered_idx]);
+//        res[scattered_idx] = ColumnMap::create(std::move(new_columns));
+//    }
+//
+//
+//    return res;
+//}
+
+
+void ColumnMap::reserve(size_t n) {
+    get_keys().reserve(n);
+    get_values().reserve(n);
+}
+
+size_t ColumnMap::byte_size() const {
+    return get_keys().byte_size() + get_values().byte_size();
+}
+
+size_t ColumnMap::allocated_bytes() const {
+    return get_keys().allocated_bytes() + get_values().allocated_bytes();
+}
+
+void ColumnMap::protect() {
+    get_keys().protect();
+    get_values().protect();
+}
+
+void ColumnMap::get_extremes(Field & min, Field & max) const {
+    Map min_map(2);
+    Map max_map(2);
+
+    keys->get_extremes(min_map[0], max_map[0]);
+    values->get_extremes(min_map[1], max_map[1]);

Review Comment:
   should get index of min/max key, and get min/max value by the index of 
min/max key



##########
be/src/olap/types.h:
##########
@@ -430,6 +431,103 @@ class ArrayTypeInfo : public TypeInfo {
     TypeInfoPtr _item_type_info;
     const size_t _item_size;
 };
+///====================== MapType Info ==========================///
+class MapTypeInfo : public TypeInfo {
+public:
+    explicit MapTypeInfo(TypeInfoPtr key_type_info, TypeInfoPtr 
value_type_info)
+            : _key_type_info(std::move(key_type_info)), 
_value_type_info(std::move(value_type_info)) {}
+    ~MapTypeInfo() override = default;
+
+    inline bool equal(const void* left, const void* right) const override {
+        auto l_value = reinterpret_cast<const MapValue*>(left);
+        auto r_value = reinterpret_cast<const MapValue*>(right);
+       return l_value->size() == r_value->size();

Review Comment:
   should also check key and value type



##########
be/src/olap/types.h:
##########
@@ -430,6 +431,103 @@ class ArrayTypeInfo : public TypeInfo {
     TypeInfoPtr _item_type_info;
     const size_t _item_size;
 };
+///====================== MapType Info ==========================///
+class MapTypeInfo : public TypeInfo {
+public:
+    explicit MapTypeInfo(TypeInfoPtr key_type_info, TypeInfoPtr 
value_type_info)
+            : _key_type_info(std::move(key_type_info)), 
_value_type_info(std::move(value_type_info)) {}

Review Comment:
   std::move may be not approprate here



##########
be/src/olap/field.h:
##########
@@ -49,7 +50,7 @@ class Field {
               _index_size(column.index_length()),
               _is_nullable(column.is_nullable()),
               _unique_id(column.unique_id()) {
-        if (column.type() == OLAP_FIELD_TYPE_ARRAY) {
+        if (column.type() == OLAP_FIELD_TYPE_ARRAY ||  column.type() == 
OLAP_FIELD_TYPE_MAP) {
             _agg_info = get_aggregate_info(column.aggregation(), column.type(),
                                            column.get_sub_column(0).type());

Review Comment:
   is it right to just use key type for map?



##########
be/src/olap/types.cpp:
##########
@@ -218,6 +233,11 @@ TypeInfoPtr get_type_info(const TabletColumn* col) {
 TypeInfoPtr clone_type_info(const TypeInfo* type_info) {
     if (is_scalar_type(type_info->type())) {
         return create_static_type_info_ptr(type_info);
+    } else if (type_info->type() == OLAP_FIELD_TYPE_MAP) {
+        const auto map_type_info = dynamic_cast<const MapTypeInfo*>(type_info);
+        return create_dynamic_type_info_ptr(
+                new 
MapTypeInfo(clone_type_info(map_type_info->get_key_type_info()),
+                                
clone_type_info(map_type_info->get_value_type_info())));
     } else {

Review Comment:
   add check for array type



##########
be/src/olap/field.h:
##########
@@ -450,6 +451,29 @@ uint32_t Field::hash_code(const CellType& cell, uint32_t 
seed) const {
     return _type_info->hash_code(cell.cell_ptr(), seed);
 }
 
+class MapField : public Field {
+public:
+    explicit MapField(const TabletColumn& column) : Field(column) {}
+
+    void consume(RowCursorCell* dst, const char* src, bool src_null, MemPool* 
mem_pool,
+                 ObjectPool* agg_pool) const override {
+        dst->set_is_null(src_null);
+        if (src_null) {
+            return;
+        }
+        _type_info->deep_copy(dst->mutable_cell_ptr(), src, mem_pool);
+    }
+
+        // make variable_ptr memory allocate to cell_ptr as MapValue
+    char* allocate_memory(char* cell_ptr, char* variable_ptr) const override {
+        return variable_ptr + _length;
+    }
+
+    size_t get_variable_len() const override {
+        return _length;

Review Comment:
   how is _length caculated?



##########
be/src/olap/rowset/segment_v2/column_writer.cpp:
##########
@@ -695,5 +808,120 @@ Status ArrayColumnWriter::finish_current_page() {
     return Status::NotSupported("array writer has no data, can not 
finish_current_page");
 }
 
+/// ============================= MapColumnWriter =====================////
+MapColumnWriter::MapColumnWriter(const ColumnWriterOptions& opts, 
std::unique_ptr<Field> field,
+                                     ScalarColumnWriter* null_writer,
+                                     std::unique_ptr<ColumnWriter> key_writer,
+                                     std::unique_ptr<ColumnWriter> 
value_writer)
+        : ColumnWriter(std::move(field), opts.meta->is_nullable()),
+          _key_writer(std::move(key_writer)),
+          _value_writer(std::move(value_writer)),
+          _opts(opts) {
+    if (is_nullable()) {
+        _null_writer.reset(null_writer);
+    }
+}
+
+Status MapColumnWriter::init() {
+    if (is_nullable()) {
+        RETURN_IF_ERROR(_null_writer->init());
+    }
+    RETURN_IF_ERROR(_key_writer->init());
+    RETURN_IF_ERROR(_value_writer->init());
+    return Status::OK();
+}
+
+uint64_t MapColumnWriter::estimate_buffer_size() {
+    size_t estimate =  _key_writer->estimate_buffer_size() +
+                      _value_writer->estimate_buffer_size();
+    if (is_nullable()) {
+        estimate += _null_writer->estimate_buffer_size();
+    }
+    return estimate;
+}
+
+Status MapColumnWriter::finish() {
+    if (is_nullable()) {
+        RETURN_IF_ERROR(_null_writer->finish());
+    }
+    RETURN_IF_ERROR(_key_writer->finish());
+    RETURN_IF_ERROR(_value_writer->finish());
+    return Status::OK();
+}
+
+// todo. make keys and values write
+Status MapColumnWriter::append_data(const uint8_t** ptr, size_t num_rows) {
+    size_t remaining = num_rows;
+    const auto* col_cursor = reinterpret_cast<const MapValue*>(*ptr);
+    while (remaining > 0) {
+        size_t num_written = 1;
+        auto* key_data_ptr = 
const_cast<MapValue*>(col_cursor)->mutable_key_data();

Review Comment:
   just use key_data()



##########
be/src/olap/rowset/segment_v2/column_writer.cpp:
##########
@@ -695,5 +808,120 @@ Status ArrayColumnWriter::finish_current_page() {
     return Status::NotSupported("array writer has no data, can not 
finish_current_page");
 }
 
+/// ============================= MapColumnWriter =====================////
+MapColumnWriter::MapColumnWriter(const ColumnWriterOptions& opts, 
std::unique_ptr<Field> field,
+                                     ScalarColumnWriter* null_writer,
+                                     std::unique_ptr<ColumnWriter> key_writer,
+                                     std::unique_ptr<ColumnWriter> 
value_writer)
+        : ColumnWriter(std::move(field), opts.meta->is_nullable()),
+          _key_writer(std::move(key_writer)),
+          _value_writer(std::move(value_writer)),
+          _opts(opts) {
+    if (is_nullable()) {
+        _null_writer.reset(null_writer);
+    }
+}
+
+Status MapColumnWriter::init() {
+    if (is_nullable()) {
+        RETURN_IF_ERROR(_null_writer->init());
+    }
+    RETURN_IF_ERROR(_key_writer->init());
+    RETURN_IF_ERROR(_value_writer->init());
+    return Status::OK();
+}
+
+uint64_t MapColumnWriter::estimate_buffer_size() {
+    size_t estimate =  _key_writer->estimate_buffer_size() +
+                      _value_writer->estimate_buffer_size();
+    if (is_nullable()) {
+        estimate += _null_writer->estimate_buffer_size();
+    }
+    return estimate;
+}
+
+Status MapColumnWriter::finish() {
+    if (is_nullable()) {
+        RETURN_IF_ERROR(_null_writer->finish());
+    }
+    RETURN_IF_ERROR(_key_writer->finish());
+    RETURN_IF_ERROR(_value_writer->finish());
+    return Status::OK();
+}
+
+// todo. make keys and values write
+Status MapColumnWriter::append_data(const uint8_t** ptr, size_t num_rows) {
+    size_t remaining = num_rows;
+    const auto* col_cursor = reinterpret_cast<const MapValue*>(*ptr);
+    while (remaining > 0) {
+        size_t num_written = 1;
+        auto* key_data_ptr = 
const_cast<MapValue*>(col_cursor)->mutable_key_data();
+       const uint8_t* key_ptr = (const uint8_t*)key_data_ptr;
+       RETURN_IF_ERROR(_key_writer->append_data(&key_ptr, 1));
+        auto* val_data_ptr = 
const_cast<MapValue*>(col_cursor)->mutable_value_data();
+       const uint8_t* val_ptr = (const uint8_t*)val_data_ptr;
+       RETURN_IF_ERROR(_value_writer->append_data(&val_ptr, 1));
+        remaining -= num_written;
+        col_cursor += num_written;
+        *ptr += num_written * sizeof(MapValue);
+    }
+
+    if (is_nullable()) {
+        return write_null_column(num_rows, false);
+    }
+    return Status::OK();
+}
+
+Status MapColumnWriter::write_data() {
+    if (is_nullable()) {
+        RETURN_IF_ERROR(_null_writer->write_data());
+    }
+    RETURN_IF_ERROR(_offset_writer->write_data());
+    RETURN_IF_ERROR(_key_writer->write_data());
+    RETURN_IF_ERROR(_value_writer->write_data());
+    return Status::OK();
+}
+
+Status MapColumnWriter::write_ordinal_index() {
+    if (is_nullable()) {
+        RETURN_IF_ERROR(_null_writer->write_ordinal_index());
+    }
+    RETURN_IF_ERROR(_key_writer->write_ordinal_index());
+    RETURN_IF_ERROR(_value_writer->write_ordinal_index());
+   
+    return Status::OK();
+}
+
+Status MapColumnWriter::append_nulls(size_t num_rows) {
+    return write_null_column(num_rows, true);
+}
+
+Status MapColumnWriter::write_null_column(size_t num_rows, bool is_null) {
+    uint8_t null_sign = is_null ? 1 : 0;
+    while (num_rows > 0) {
+        // TODO llj bulk write
+        const uint8_t* null_sign_ptr = &null_sign;
+        RETURN_IF_ERROR(_null_writer->append_data(&null_sign_ptr, 1));

Review Comment:
   bulk write



##########
be/src/olap/rowset/segment_v2/column_reader.cpp:
##########
@@ -449,13 +478,97 @@ Status ColumnReader::new_iterator(ColumnIterator** 
iterator) {
                     null_iterator);
             return Status::OK();
         }
+       case FieldType::OLAP_FIELD_TYPE_MAP: {
+            ColumnIterator* key_iterator = nullptr;
+            RETURN_IF_ERROR(_sub_readers[0]->new_iterator(&key_iterator));
+            ColumnIterator* val_iterator = nullptr;
+            RETURN_IF_ERROR(_sub_readers[1]->new_iterator(&val_iterator));
+            ColumnIterator* null_iterator = nullptr;
+            if (is_nullable()) {
+                RETURN_IF_ERROR(_sub_readers[2]->new_iterator(&null_iterator));
+            }
+            *iterator = new MapFileColumnIterator(this,null_iterator,
+                                                  key_iterator, val_iterator);
+            return Status::OK();
+        }
         default:
             return Status::NotSupported("unsupported type to create iterator: 
{}",
                                         std::to_string(type));
         }
     }
 }
 
+///====================== MapFileColumnIterator 
============================////
+MapFileColumnIterator::MapFileColumnIterator(ColumnReader* reader, 
ColumnIterator* null_iterator,
+                                                 ColumnIterator* key_iterator,
+                                                 ColumnIterator* val_iterator)
+        : _map_reader(reader) {
+    _key_iterator.reset(key_iterator);
+    _val_iterator.reset(val_iterator);
+    if (_map_reader->is_nullable()) {
+        _null_iterator.reset(null_iterator);
+    }
+}
+
+Status MapFileColumnIterator::init(const ColumnIteratorOptions& opts) {
+    RETURN_IF_ERROR(_key_iterator->init(opts));
+    RETURN_IF_ERROR(_val_iterator->init(opts));
+    if (_map_reader->is_nullable()) {
+        RETURN_IF_ERROR(_null_iterator->init(opts));
+    }
+    return Status::OK();
+}
+
+Status MapFileColumnIterator::_peek_one_offset(ordinal_t* offset) {
+    return Status::OK();
+}
+
+Status MapFileColumnIterator::next_batch(size_t* n, ColumnBlockView* dst, 
bool* has_null) {
+    return Status::OK();

Review Comment:
   return error



##########
be/src/vec/functions/array/function_array_element.h:
##########
@@ -44,12 +46,18 @@ class FunctionArrayElement : public IFunction {
     size_t get_number_of_arguments() const override { return 2; }
 
     DataTypePtr get_return_type_impl(const DataTypes& arguments) const 
override {
-        DCHECK(is_array(arguments[0]))
-                << "first argument for function: " << name << " should be 
DataTypeArray";
-        DCHECK(is_integer(arguments[1]))
-                << "second argument for function: " << name << " should be 
Integer";
-        return make_nullable(
-                
check_and_get_data_type<DataTypeArray>(arguments[0].get())->get_nested_type());
+        DCHECK(is_array(arguments[0]) || is_map(arguments[0]))
+                << "first argument for function: " << name << " should be 
DataTypeArray or DataTypeMap";
+        if (is_array(arguments[0])) {
+            DCHECK(is_integer(arguments[1])) << "second argument for function: 
" << name << " should be Integer for array element";
+            return make_nullable(
+                    
check_and_get_data_type<DataTypeArray>(arguments[0].get())->get_nested_type());
+        } else {

Review Comment:
   check map type



##########
be/src/olap/rowset/segment_v2/column_reader.cpp:
##########
@@ -449,13 +478,97 @@ Status ColumnReader::new_iterator(ColumnIterator** 
iterator) {
                     null_iterator);
             return Status::OK();
         }
+       case FieldType::OLAP_FIELD_TYPE_MAP: {
+            ColumnIterator* key_iterator = nullptr;
+            RETURN_IF_ERROR(_sub_readers[0]->new_iterator(&key_iterator));
+            ColumnIterator* val_iterator = nullptr;
+            RETURN_IF_ERROR(_sub_readers[1]->new_iterator(&val_iterator));
+            ColumnIterator* null_iterator = nullptr;
+            if (is_nullable()) {
+                RETURN_IF_ERROR(_sub_readers[2]->new_iterator(&null_iterator));
+            }
+            *iterator = new MapFileColumnIterator(this,null_iterator,
+                                                  key_iterator, val_iterator);
+            return Status::OK();
+        }
         default:
             return Status::NotSupported("unsupported type to create iterator: 
{}",
                                         std::to_string(type));
         }
     }
 }
 
+///====================== MapFileColumnIterator 
============================////
+MapFileColumnIterator::MapFileColumnIterator(ColumnReader* reader, 
ColumnIterator* null_iterator,
+                                                 ColumnIterator* key_iterator,
+                                                 ColumnIterator* val_iterator)
+        : _map_reader(reader) {
+    _key_iterator.reset(key_iterator);
+    _val_iterator.reset(val_iterator);
+    if (_map_reader->is_nullable()) {
+        _null_iterator.reset(null_iterator);
+    }
+}
+
+Status MapFileColumnIterator::init(const ColumnIteratorOptions& opts) {
+    RETURN_IF_ERROR(_key_iterator->init(opts));
+    RETURN_IF_ERROR(_val_iterator->init(opts));
+    if (_map_reader->is_nullable()) {
+        RETURN_IF_ERROR(_null_iterator->init(opts));
+    }
+    return Status::OK();
+}
+
+Status MapFileColumnIterator::_peek_one_offset(ordinal_t* offset) {
+    return Status::OK();
+}
+
+Status MapFileColumnIterator::next_batch(size_t* n, ColumnBlockView* dst, 
bool* has_null) {
+    return Status::OK();
+}
+
+
+Status MapFileColumnIterator::seek_to_ordinal(ordinal_t ord) {
+    RETURN_IF_ERROR(_key_iterator->seek_to_ordinal(ord));
+    RETURN_IF_ERROR(_val_iterator->seek_to_ordinal(ord));
+    if (_map_reader->is_nullable()) {
+        RETURN_IF_ERROR(_null_iterator->seek_to_ordinal(ord));
+    }
+    return Status::OK();
+}
+
+Status MapFileColumnIterator::next_batch(size_t* n, 
vectorized::MutableColumnPtr& dst,
+                                           bool* has_null) {
+    const auto* column_map = 
vectorized::check_and_get_column<vectorized::ColumnMap>(
+            dst->is_nullable() ? 
static_cast<vectorized::ColumnNullable&>(*dst).get_nested_column()
+                               : *dst);
+    auto column_key_ptr = column_map->get_keys().assume_mutable();
+    auto column_val_ptr = column_map->get_values().assume_mutable();
+    RETURN_IF_ERROR(_key_iterator->next_batch(n, column_key_ptr, has_null));
+    RETURN_IF_ERROR(_val_iterator->next_batch(n, column_val_ptr, has_null));
+
+    if (dst->is_nullable()) {
+        auto null_map_ptr =
+                
static_cast<vectorized::ColumnNullable&>(*dst).get_null_map_column_ptr();
+        size_t num_read = *n;
+        bool null_signs_has_null = false;
+        RETURN_IF_ERROR(_null_iterator->next_batch(&num_read, null_map_ptr, 
&null_signs_has_null));
+        DCHECK(num_read == *n);
+    }
+    return Status::OK();
+}
+
+Status MapFileColumnIterator::read_by_rowids(const rowid_t* rowids, const 
size_t count,
+                                               vectorized::MutableColumnPtr& 
dst) {
+    for (size_t i = 0; i < count; ++i) {
+        RETURN_IF_ERROR(seek_to_ordinal(rowids[i]));
+        size_t num_read = 1;
+        RETURN_IF_ERROR(next_batch(&num_read, dst, nullptr));

Review Comment:
   is nullptr always right?



##########
be/src/runtime/map_value.h:
##########
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <type_traits>
+#include "runtime/primitive_type.h"
+
+namespace doris_udf {
+class FunctionContext;
+struct AnyVal;
+} // namespace doris_udf
+
+namespace doris {
+
+using doris_udf::FunctionContext;
+using doris_udf::AnyVal;
+
+/**
+ * MapValue is for map type in memory
+ */
+class MapValue {
+public:
+    MapValue() = default;
+
+    explicit MapValue(int32_t length)
+            : _key_data(nullptr), _value_data(nullptr), _length(length){}

Review Comment:
   it's not valid if _key/value_data is null and _length > 0



##########
be/src/olap/rowset/segment_v2/column_reader.h:
##########
@@ -393,6 +393,44 @@ class EmptyFileColumnIterator final : public 
ColumnIterator {
     ordinal_t get_current_ordinal() const override { return 0; }
 };
 
+// This iterator is used to read map value column
+class MapFileColumnIterator final : public ColumnIterator {
+public:
+    explicit MapFileColumnIterator(ColumnReader* reader, ColumnIterator* 
null_iterator,
+                                   ColumnIterator* key_iterator, 
ColumnIterator* val_iterator);
+
+    ~MapFileColumnIterator() override = default;
+
+    Status init(const ColumnIteratorOptions& opts) override;
+
+    Status next_batch(size_t* n, ColumnBlockView* dst, bool* has_null) 
override;
+
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr& dst, bool* 
has_null) override;
+
+    Status read_by_rowids(const rowid_t* rowids, const size_t count,
+                          vectorized::MutableColumnPtr& dst) override;
+
+    Status seek_to_first() override {
+        RETURN_IF_ERROR(_key_iterator->seek_to_first());
+        RETURN_IF_ERROR(_val_iterator->seek_to_first());
+        return Status::OK();
+    }
+
+    Status seek_to_ordinal(ordinal_t ord) override;
+
+    ordinal_t get_current_ordinal() const override {
+        return _key_iterator->get_current_ordinal();
+    }
+
+private:
+    ColumnReader* _map_reader; // need ?

Review Comment:
   it is used for nullable check



##########
be/src/runtime/map_value.h:
##########
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <type_traits>
+#include "runtime/primitive_type.h"
+
+namespace doris_udf {
+class FunctionContext;
+struct AnyVal;
+} // namespace doris_udf
+
+namespace doris {
+
+using doris_udf::FunctionContext;
+using doris_udf::AnyVal;
+
+/**
+ * MapValue is for map type in memory
+ */
+class MapValue {
+public:
+    MapValue() = default;
+
+    explicit MapValue(int32_t length)
+            : _key_data(nullptr), _value_data(nullptr), _length(length){}
+
+    MapValue(void* k_data, void* v_data, int32_t length)
+            : _key_data(k_data), _value_data(v_data), _length(length) {}
+
+    void to_map_val(MapVal* val) const;
+
+    int32_t size() const { return _length; }
+
+    int32_t length() const { return _length; }
+
+    void shallow_copy(const MapValue* other);

Review Comment:
   is deep_copy needed?



##########
be/src/olap/types.h:
##########
@@ -430,6 +431,103 @@ class ArrayTypeInfo : public TypeInfo {
     TypeInfoPtr _item_type_info;
     const size_t _item_size;
 };
+///====================== MapType Info ==========================///
+class MapTypeInfo : public TypeInfo {
+public:
+    explicit MapTypeInfo(TypeInfoPtr key_type_info, TypeInfoPtr 
value_type_info)
+            : _key_type_info(std::move(key_type_info)), 
_value_type_info(std::move(value_type_info)) {}
+    ~MapTypeInfo() override = default;
+
+    inline bool equal(const void* left, const void* right) const override {
+        auto l_value = reinterpret_cast<const MapValue*>(left);
+        auto r_value = reinterpret_cast<const MapValue*>(right);
+       return l_value->size() == r_value->size();
+    }
+
+    int cmp(const void* left, const void* right) const override {
+        auto l_value = reinterpret_cast<const MapValue*>(left);
+        auto r_value = reinterpret_cast<const MapValue*>(right);
+        uint32_t l_size = l_value->size();
+        uint32_t r_size = r_value->size();
+       if (l_size < r_size) {
+            return -1;
+        } else if (l_size > r_size) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    void shallow_copy(void* dest, const void* src) const override {
+        auto dest_value = reinterpret_cast<MapValue*>(dest);
+        auto src_value = reinterpret_cast<const MapValue*>(src);
+        dest_value->shallow_copy(src_value);
+    }
+
+    void deep_copy(void* dest, const void* src, MemPool* mem_pool) const 
override {
+        DCHECK(false);
+
+    }
+
+    void copy_object(void* dest, const void* src, MemPool* mem_pool) const 
override {
+        deep_copy(dest, src, mem_pool);
+    }
+
+    void direct_copy(void* dest, const void* src) const override {
+        CHECK(false);
+    }
+
+    void direct_copy(uint8_t** base, void* dest, const void* src) const {
+        CHECK(false);
+    }
+
+    void direct_copy_may_cut(void* dest, const void* src) const override { 
direct_copy(dest, src); }
+
+    Status convert_from(void* dest, const void* src, const TypeInfo* src_type, 
MemPool* mem_pool,
+                        size_t variable_len = 0) const override {
+        return Status::Error<ErrorCode::NOT_IMPLEMENTED_ERROR>();
+    }
+
+    Status from_string(void* buf, const std::string& scan_key, const int 
precision = 0,
+                       const int scale = 0) const override {
+        return Status::Error<ErrorCode::NOT_IMPLEMENTED_ERROR>();
+    }
+
+    std::string to_string(const void* src) const override {
+        return "{}";
+    }
+
+    void set_to_max(void* buf) const override {
+        DCHECK(false) << "set_to_max of list is not implemented.";
+    }
+
+    void set_to_min(void* buf) const override {
+        DCHECK(false) << "set_to_min of list is not implemented.";
+    }
+
+    uint32_t hash_code(const void* data, uint32_t seed) const override {
+        auto map_value = reinterpret_cast<const MapValue*>(data);
+        auto size = map_value->size();
+        uint32_t result = HashUtil::hash(&size, sizeof(size), seed);
+        result = seed * result + _key_type_info->hash_code(
+                                         map_value->key_data(), seed)
+                 + _value_type_info->hash_code(
+                           map_value->value_data(), seed);
+        return result;
+    }
+
+     // todo . is here only to need return 16 for two ptr?
+    const size_t size() const override { return 16; }

Review Comment:
   ?



##########
be/src/vec/sink/vmysql_result_writer.cpp:
##########
@@ -186,6 +188,58 @@ Status VMysqlResultWriter::_add_one_column(const 
ColumnPtr& column_ptr,
             _buffer.close_dynamic_mode();
             result->result_batch.rows[i].append(_buffer.buf(), 
_buffer.length());
         }
+    } else if constexpr (type == TYPE_MAP) {
+               auto& column_map = assert_cast<const ColumnMap&>(*column);
+        auto& offsets = column_map.get_offsets();
+        auto& column_key_array = assert_cast<const 
ColumnArray&>(column_map.get_keys());
+        auto& column_val_array = assert_cast<const 
ColumnArray&>(column_map.get_values());
+        auto& map_type = assert_cast<const DataTypeMap&>(*nested_type_ptr);
+        auto& key_nested_type_ptr = map_type.get_key_type();
+        auto& val_nested_type_ptr = map_type.get_value_type();
+        for (ssize_t i = 0; i < row_size; ++i) {
+            if (0 != buf_ret) {
+                return Status::InternalError("pack mysql buffer failed.");
+            }
+            _buffer.reset();
+
+            _buffer.open_dynamic_mode();
+            buf_ret = _buffer.push_string("{", 1);

Review Comment:
   can DataTypeMap::to_string() be reused here to reduce redundant code ?



##########
be/src/olap/types.h:
##########
@@ -430,6 +431,103 @@ class ArrayTypeInfo : public TypeInfo {
     TypeInfoPtr _item_type_info;
     const size_t _item_size;
 };
+///====================== MapType Info ==========================///
+class MapTypeInfo : public TypeInfo {
+public:
+    explicit MapTypeInfo(TypeInfoPtr key_type_info, TypeInfoPtr 
value_type_info)
+            : _key_type_info(std::move(key_type_info)), 
_value_type_info(std::move(value_type_info)) {}
+    ~MapTypeInfo() override = default;
+
+    inline bool equal(const void* left, const void* right) const override {
+        auto l_value = reinterpret_cast<const MapValue*>(left);
+        auto r_value = reinterpret_cast<const MapValue*>(right);
+       return l_value->size() == r_value->size();
+    }
+
+    int cmp(const void* left, const void* right) const override {
+        auto l_value = reinterpret_cast<const MapValue*>(left);
+        auto r_value = reinterpret_cast<const MapValue*>(right);
+        uint32_t l_size = l_value->size();
+        uint32_t r_size = r_value->size();
+       if (l_size < r_size) {
+            return -1;
+        } else if (l_size > r_size) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    void shallow_copy(void* dest, const void* src) const override {
+        auto dest_value = reinterpret_cast<MapValue*>(dest);
+        auto src_value = reinterpret_cast<const MapValue*>(src);
+        dest_value->shallow_copy(src_value);
+    }
+
+    void deep_copy(void* dest, const void* src, MemPool* mem_pool) const 
override {
+        DCHECK(false);
+
+    }
+
+    void copy_object(void* dest, const void* src, MemPool* mem_pool) const 
override {
+        deep_copy(dest, src, mem_pool);
+    }
+
+    void direct_copy(void* dest, const void* src) const override {
+        CHECK(false);
+    }
+
+    void direct_copy(uint8_t** base, void* dest, const void* src) const {
+        CHECK(false);
+    }
+
+    void direct_copy_may_cut(void* dest, const void* src) const override { 
direct_copy(dest, src); }
+
+    Status convert_from(void* dest, const void* src, const TypeInfo* src_type, 
MemPool* mem_pool,
+                        size_t variable_len = 0) const override {
+        return Status::Error<ErrorCode::NOT_IMPLEMENTED_ERROR>();
+    }
+
+    Status from_string(void* buf, const std::string& scan_key, const int 
precision = 0,
+                       const int scale = 0) const override {
+        return Status::Error<ErrorCode::NOT_IMPLEMENTED_ERROR>();
+    }
+
+    std::string to_string(const void* src) const override {
+        return "{}";

Review Comment:
   not valid



##########
be/src/runtime/types.cpp:
##########
@@ -191,6 +197,14 @@ TypeDescriptor::TypeDescriptor(const 
google::protobuf::RepeatedPtrField<PTypeNod
         children.push_back(TypeDescriptor(types, idx));
         break;
     }
+    case TTypeNodeType::MAP: {
+        type = TYPE_MAP;

Review Comment:
   has_contains_null is missed



##########
be/src/vec/functions/array/function_array_element.h:
##########
@@ -81,6 +94,79 @@ class FunctionArrayElement : public IFunction {
     }
 
 private:
+    //=========================== map element===========================//
+    ColumnPtr _get_mapped_idx(const ColumnArray& key_column,
+                           const ColumnWithTypeAndName& argument) {
+        if (key_column.get_data().is_column_string()) {
+            return _mapped_key_string(key_column, argument);

Review Comment:
   key compare can be unified for all type using column.compare_at



##########
be/src/olap/types.h:
##########
@@ -430,6 +431,103 @@ class ArrayTypeInfo : public TypeInfo {
     TypeInfoPtr _item_type_info;
     const size_t _item_size;
 };
+///====================== MapType Info ==========================///
+class MapTypeInfo : public TypeInfo {
+public:
+    explicit MapTypeInfo(TypeInfoPtr key_type_info, TypeInfoPtr 
value_type_info)
+            : _key_type_info(std::move(key_type_info)), 
_value_type_info(std::move(value_type_info)) {}
+    ~MapTypeInfo() override = default;
+
+    inline bool equal(const void* left, const void* right) const override {
+        auto l_value = reinterpret_cast<const MapValue*>(left);
+        auto r_value = reinterpret_cast<const MapValue*>(right);
+       return l_value->size() == r_value->size();
+    }
+
+    int cmp(const void* left, const void* right) const override {
+        auto l_value = reinterpret_cast<const MapValue*>(left);
+        auto r_value = reinterpret_cast<const MapValue*>(right);
+        uint32_t l_size = l_value->size();
+        uint32_t r_size = r_value->size();
+       if (l_size < r_size) {
+            return -1;
+        } else if (l_size > r_size) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    void shallow_copy(void* dest, const void* src) const override {
+        auto dest_value = reinterpret_cast<MapValue*>(dest);
+        auto src_value = reinterpret_cast<const MapValue*>(src);
+        dest_value->shallow_copy(src_value);
+    }
+
+    void deep_copy(void* dest, const void* src, MemPool* mem_pool) const 
override {
+        DCHECK(false);

Review Comment:
   add impl



##########
be/src/olap/field.h:
##########
@@ -792,6 +824,15 @@ class FieldFactory {
                 local->add_sub_field(std::move(item_field));
                 return local;
             }
+           case OLAP_FIELD_TYPE_MAP: {

Review Comment:
   we should consider if array/map is valid in value column of agg table



##########
be/src/vec/functions/array/function_array_element.h:
##########
@@ -81,6 +94,79 @@ class FunctionArrayElement : public IFunction {
     }
 
 private:
+    //=========================== map element===========================//
+    ColumnPtr _get_mapped_idx(const ColumnArray& key_column,
+                           const ColumnWithTypeAndName& argument) {
+        if (key_column.get_data().is_column_string()) {
+            return _mapped_key_string(key_column, argument);
+        }
+        return nullptr;
+    }
+
+    ColumnPtr _get_mapped_value(const ColumnArray& val_column,

Review Comment:
   useless method



##########
be/src/olap/rowset/segment_v2/column_writer.cpp:
##########
@@ -173,6 +173,119 @@ Status ColumnWriter::create(const ColumnWriterOptions& 
opts, const TabletColumn*
             *writer = std::move(writer_local);
             return Status::OK();
         }
+       case FieldType::OLAP_FIELD_TYPE_MAP: {
+            DCHECK(column->get_subtype_count() == 2);
+            // todo . here key and value is array only?
+            const TabletColumn& key_column = column->get_sub_column(0); // 
field_type is true key and value
+            const TabletColumn& value_column = column->get_sub_column(1);
+
+            // create null writer
+            ScalarColumnWriter* null_writer = nullptr;
+            if (opts.meta->is_nullable()) {
+                FieldType null_type = FieldType::OLAP_FIELD_TYPE_TINYINT;
+                ColumnWriterOptions null_options;
+                null_options.meta = opts.meta->add_children_columns();
+                null_options.meta->set_column_id(3);
+                null_options.meta->set_unique_id(3);
+                null_options.meta->set_type(null_type);
+                null_options.meta->set_is_nullable(false);
+                null_options.meta->set_length(
+                        
get_scalar_type_info<OLAP_FIELD_TYPE_TINYINT>()->size());
+                null_options.meta->set_encoding(DEFAULT_ENCODING);
+                null_options.meta->set_compression(opts.meta->compression());
+
+                null_options.need_zone_map = false;
+                null_options.need_bloom_filter = false;
+                null_options.need_bitmap_index = false;
+
+                TabletColumn null_column = TabletColumn(
+                        OLAP_FIELD_AGGREGATION_NONE, null_type, false,
+                        null_options.meta->unique_id(), 
null_options.meta->length());
+                null_column.set_name("nullable");
+                null_column.set_index_length(-1); // no short key index
+                std::unique_ptr<Field> 
null_field(FieldFactory::create(null_column));
+                null_writer =
+                        new ScalarColumnWriter(null_options, 
std::move(null_field), file_writer);
+            }
+
+            // create key writer
+            std::unique_ptr<ColumnWriter> key_writer;
+           ColumnWriterOptions key_opts;
+            TabletColumn key_list_column(OLAP_FIELD_AGGREGATION_NONE, 
OLAP_FIELD_TYPE_ARRAY);
+            {
+               
key_list_column.add_sub_column(const_cast<TabletColumn&>(key_column));
+//                key_list_column.add_sub_column(key_column);
+                key_list_column.set_name("map.key");
+                key_list_column.set_index_length(-1);
+
+
+                key_opts.meta = opts.meta->mutable_children_columns(0);
+                key_opts.meta->set_column_id(4);
+                key_opts.meta->set_unique_id(4);
+                key_opts.meta->set_type(OLAP_FIELD_TYPE_ARRAY);
+                key_opts.meta->set_length(0);
+               key_opts.meta->set_encoding(BIT_SHUFFLE);

Review Comment:
   hardcoded encoding



##########
be/src/olap/rowset/segment_v2/column_writer.cpp:
##########
@@ -173,6 +173,119 @@ Status ColumnWriter::create(const ColumnWriterOptions& 
opts, const TabletColumn*
             *writer = std::move(writer_local);
             return Status::OK();
         }
+       case FieldType::OLAP_FIELD_TYPE_MAP: {

Review Comment:
   this code need to be refactor and cleaned



##########
be/src/olap/rowset/segment_v2/column_reader.cpp:
##########
@@ -449,13 +478,97 @@ Status ColumnReader::new_iterator(ColumnIterator** 
iterator) {
                     null_iterator);
             return Status::OK();
         }
+       case FieldType::OLAP_FIELD_TYPE_MAP: {
+            ColumnIterator* key_iterator = nullptr;
+            RETURN_IF_ERROR(_sub_readers[0]->new_iterator(&key_iterator));
+            ColumnIterator* val_iterator = nullptr;
+            RETURN_IF_ERROR(_sub_readers[1]->new_iterator(&val_iterator));
+            ColumnIterator* null_iterator = nullptr;
+            if (is_nullable()) {
+                RETURN_IF_ERROR(_sub_readers[2]->new_iterator(&null_iterator));
+            }
+            *iterator = new MapFileColumnIterator(this,null_iterator,
+                                                  key_iterator, val_iterator);
+            return Status::OK();
+        }
         default:
             return Status::NotSupported("unsupported type to create iterator: 
{}",
                                         std::to_string(type));
         }
     }
 }
 
+///====================== MapFileColumnIterator 
============================////
+MapFileColumnIterator::MapFileColumnIterator(ColumnReader* reader, 
ColumnIterator* null_iterator,
+                                                 ColumnIterator* key_iterator,
+                                                 ColumnIterator* val_iterator)
+        : _map_reader(reader) {
+    _key_iterator.reset(key_iterator);
+    _val_iterator.reset(val_iterator);
+    if (_map_reader->is_nullable()) {
+        _null_iterator.reset(null_iterator);
+    }
+}
+
+Status MapFileColumnIterator::init(const ColumnIteratorOptions& opts) {
+    RETURN_IF_ERROR(_key_iterator->init(opts));
+    RETURN_IF_ERROR(_val_iterator->init(opts));
+    if (_map_reader->is_nullable()) {
+        RETURN_IF_ERROR(_null_iterator->init(opts));
+    }
+    return Status::OK();
+}
+
+Status MapFileColumnIterator::_peek_one_offset(ordinal_t* offset) {
+    return Status::OK();

Review Comment:
   return error



##########
be/src/olap/rowset/segment_v2/column_writer.cpp:
##########
@@ -173,6 +173,119 @@ Status ColumnWriter::create(const ColumnWriterOptions& 
opts, const TabletColumn*
             *writer = std::move(writer_local);
             return Status::OK();
         }
+       case FieldType::OLAP_FIELD_TYPE_MAP: {
+            DCHECK(column->get_subtype_count() == 2);
+            // todo . here key and value is array only?
+            const TabletColumn& key_column = column->get_sub_column(0); // 
field_type is true key and value
+            const TabletColumn& value_column = column->get_sub_column(1);
+
+            // create null writer
+            ScalarColumnWriter* null_writer = nullptr;
+            if (opts.meta->is_nullable()) {
+                FieldType null_type = FieldType::OLAP_FIELD_TYPE_TINYINT;
+                ColumnWriterOptions null_options;
+                null_options.meta = opts.meta->add_children_columns();
+                null_options.meta->set_column_id(3);
+                null_options.meta->set_unique_id(3);
+                null_options.meta->set_type(null_type);
+                null_options.meta->set_is_nullable(false);
+                null_options.meta->set_length(
+                        
get_scalar_type_info<OLAP_FIELD_TYPE_TINYINT>()->size());
+                null_options.meta->set_encoding(DEFAULT_ENCODING);
+                null_options.meta->set_compression(opts.meta->compression());
+
+                null_options.need_zone_map = false;
+                null_options.need_bloom_filter = false;
+                null_options.need_bitmap_index = false;
+
+                TabletColumn null_column = TabletColumn(
+                        OLAP_FIELD_AGGREGATION_NONE, null_type, false,
+                        null_options.meta->unique_id(), 
null_options.meta->length());
+                null_column.set_name("nullable");
+                null_column.set_index_length(-1); // no short key index
+                std::unique_ptr<Field> 
null_field(FieldFactory::create(null_column));
+                null_writer =
+                        new ScalarColumnWriter(null_options, 
std::move(null_field), file_writer);
+            }
+
+            // create key writer
+            std::unique_ptr<ColumnWriter> key_writer;
+           ColumnWriterOptions key_opts;
+            TabletColumn key_list_column(OLAP_FIELD_AGGREGATION_NONE, 
OLAP_FIELD_TYPE_ARRAY);
+            {
+               
key_list_column.add_sub_column(const_cast<TabletColumn&>(key_column));
+//                key_list_column.add_sub_column(key_column);
+                key_list_column.set_name("map.key");
+                key_list_column.set_index_length(-1);
+
+
+                key_opts.meta = opts.meta->mutable_children_columns(0);
+                key_opts.meta->set_column_id(4);

Review Comment:
   magic number 4



##########
be/src/olap/rowset/segment_v2/column_writer.cpp:
##########
@@ -173,6 +173,119 @@ Status ColumnWriter::create(const ColumnWriterOptions& 
opts, const TabletColumn*
             *writer = std::move(writer_local);
             return Status::OK();
         }
+       case FieldType::OLAP_FIELD_TYPE_MAP: {
+            DCHECK(column->get_subtype_count() == 2);
+            // todo . here key and value is array only?
+            const TabletColumn& key_column = column->get_sub_column(0); // 
field_type is true key and value
+            const TabletColumn& value_column = column->get_sub_column(1);
+
+            // create null writer
+            ScalarColumnWriter* null_writer = nullptr;
+            if (opts.meta->is_nullable()) {
+                FieldType null_type = FieldType::OLAP_FIELD_TYPE_TINYINT;
+                ColumnWriterOptions null_options;
+                null_options.meta = opts.meta->add_children_columns();
+                null_options.meta->set_column_id(3);
+                null_options.meta->set_unique_id(3);
+                null_options.meta->set_type(null_type);
+                null_options.meta->set_is_nullable(false);
+                null_options.meta->set_length(
+                        
get_scalar_type_info<OLAP_FIELD_TYPE_TINYINT>()->size());
+                null_options.meta->set_encoding(DEFAULT_ENCODING);
+                null_options.meta->set_compression(opts.meta->compression());
+
+                null_options.need_zone_map = false;
+                null_options.need_bloom_filter = false;
+                null_options.need_bitmap_index = false;
+
+                TabletColumn null_column = TabletColumn(
+                        OLAP_FIELD_AGGREGATION_NONE, null_type, false,
+                        null_options.meta->unique_id(), 
null_options.meta->length());
+                null_column.set_name("nullable");
+                null_column.set_index_length(-1); // no short key index
+                std::unique_ptr<Field> 
null_field(FieldFactory::create(null_column));
+                null_writer =
+                        new ScalarColumnWriter(null_options, 
std::move(null_field), file_writer);
+            }
+
+            // create key writer
+            std::unique_ptr<ColumnWriter> key_writer;
+           ColumnWriterOptions key_opts;
+            TabletColumn key_list_column(OLAP_FIELD_AGGREGATION_NONE, 
OLAP_FIELD_TYPE_ARRAY);
+            {
+               
key_list_column.add_sub_column(const_cast<TabletColumn&>(key_column));
+//                key_list_column.add_sub_column(key_column);
+                key_list_column.set_name("map.key");
+                key_list_column.set_index_length(-1);
+
+
+                key_opts.meta = opts.meta->mutable_children_columns(0);
+                key_opts.meta->set_column_id(4);
+                key_opts.meta->set_unique_id(4);
+                key_opts.meta->set_type(OLAP_FIELD_TYPE_ARRAY);
+                key_opts.meta->set_length(0);
+               key_opts.meta->set_encoding(BIT_SHUFFLE);
+                
key_opts.meta->set_compression(segment_v2::CompressionTypePB::LZ4F);

Review Comment:
   hardcoded compression



##########
be/src/vec/functions/array/function_array_element.h:
##########
@@ -81,6 +94,79 @@ class FunctionArrayElement : public IFunction {
     }
 
 private:
+    //=========================== map element===========================//
+    ColumnPtr _get_mapped_idx(const ColumnArray& key_column,
+                           const ColumnWithTypeAndName& argument) {
+        if (key_column.get_data().is_column_string()) {
+            return _mapped_key_string(key_column, argument);
+        }
+        return nullptr;
+    }
+
+    ColumnPtr _get_mapped_value(const ColumnArray& val_column,
+                                const IColumn& matched_indices,
+                                const UInt8* src_null_map,
+                                UInt8* dst_null_map) {
+        const UInt8* nested_null_map = nullptr;
+        ColumnPtr nested_column = nullptr;
+        if (is_column_nullable(val_column.get_data())) {
+            const auto& nested_null_column =
+                    reinterpret_cast<const 
ColumnNullable&>(val_column.get_data());
+            nested_null_map = 
nested_null_column.get_null_map_column().get_data().data();
+            nested_column = nested_null_column.get_nested_column_ptr();
+        } else {
+            nested_column = val_column.get_data_ptr();
+        }
+        if (check_column<ColumnInt8>(nested_column)) {
+            return _execute_number<ColumnInt8>(val_column.get_offsets(), 
*nested_column,
+                                                src_null_map, matched_indices,
+                                                nested_null_map, dst_null_map);
+        } else if (check_column<ColumnInt32>(nested_column)) {
+            _execute_number<ColumnInt32>(val_column.get_offsets(), 
*nested_column,
+                                        src_null_map, matched_indices,
+                                        nested_null_map, dst_null_map);
+        }
+        return nullptr;
+    }
+
+    ColumnPtr _mapped_key_string(const ColumnArray& column,
+                            const ColumnWithTypeAndName& argument) {
+        auto right_column = argument.column->convert_to_full_column_if_const();
+        const ColumnString& match_key = reinterpret_cast<const 
ColumnString&>(*right_column);
+        const ColumnArray::Offsets64& offsets = column.get_offsets();
+        ColumnPtr nested_ptr = nullptr;
+        if (is_column_nullable(column.get_data())) {
+            nested_ptr = reinterpret_cast<const 
ColumnNullable&>(column.get_data()).get_nested_column_ptr();
+        } else {
+            nested_ptr = column.get_data_ptr();
+        }
+        const ColumnString& nested_key = reinterpret_cast<const 
ColumnString&>(*nested_ptr);
+        size_t rows = offsets.size();
+        // prepare return data
+        auto matched_indices = ColumnVector<Int8>::create();
+        matched_indices->reserve(rows);
+
+        for (size_t i = 0; i < rows; i++)
+        {
+            bool matched = false;
+            size_t begin = offsets[i - 1];
+            size_t end = offsets[i];
+            for (size_t j = begin; j < end; j++) {
+                if (nested_key.get_data_at(j) == match_key.get_data_at(i)) {

Review Comment:
   use general compare method column.compare_at()



##########
be/src/vec/olap/olap_data_convertor.cpp:
##########
@@ -712,4 +723,79 @@ Status 
OlapBlockDataConvertor::OlapColumnDataConvertorArray::convert_to_olap(
     return Status::OK();
 }
 
+Status OlapBlockDataConvertor::OlapColumnDataConvertorMap::convert_to_olap() {
+    const ColumnMap* column_map = nullptr;
+    const DataTypeMap* data_type_map = nullptr;
+    if (_nullmap) {
+        const auto* nullable_column =
+                assert_cast<const ColumnNullable*>(_typed_column.column.get());
+        column_map =
+                assert_cast<const 
ColumnMap*>(nullable_column->get_nested_column_ptr().get());
+        data_type_map = assert_cast<const DataTypeMap*>(
+                (assert_cast<const 
DataTypeNullable*>(_typed_column.type.get())->get_nested_type())
+                        .get());
+    } else {
+        column_map = assert_cast<const ColumnMap*>(_typed_column.column.get());
+        data_type_map = assert_cast<const 
DataTypeMap*>(_typed_column.type.get());
+    }
+    assert(column_map);
+    assert(data_type_map);
+
+    return convert_to_olap(column_map, data_type_map);
+}
+
+Status OlapBlockDataConvertor::OlapColumnDataConvertorMap::convert_to_olap(
+        const ColumnMap* column_map,
+        const DataTypeMap* data_type_map) {
+
+    ColumnPtr key_data = column_map->get_keys_ptr();
+    ColumnPtr value_data = column_map->get_values_ptr();
+    if (column_map->get_keys().is_nullable()) {
+        const auto& key_nullable_column =
+                assert_cast<const ColumnNullable&>(column_map->get_keys());
+        key_data = key_nullable_column.get_nested_column_ptr();
+    }
+
+    if (column_map->get_values().is_nullable()) {
+        const auto& val_nullable_column =
+                assert_cast<const ColumnNullable&>(column_map->get_values());
+        value_data = val_nullable_column.get_nested_column_ptr();
+    }
+
+    const auto& offsets = column_map->get_offsets(); // use keys offsets
+
+    ColumnWithTypeAndName key_typed_column = {
+            key_data, remove_nullable(data_type_map->get_keys()),"map.key"};
+    _key_convertor->set_source_column(key_typed_column, _row_pos, _num_rows);
+    _key_convertor->convert_to_olap();
+
+    ColumnWithTypeAndName value_typed_column = {
+            value_data, remove_nullable(data_type_map->get_values()), 
"map.value"};
+    _value_convertor->set_source_column(value_typed_column, _row_pos, 
_num_rows);
+    _value_convertor->convert_to_olap();
+
+    MapValue* map_value = _values.data();
+    for (size_t i = 0; i < _num_rows; ++i, ++map_value) {
+        int64_t cur_pos = _row_pos + i;
+        int64_t prev_pos = cur_pos - 1;
+        if (_nullmap && _nullmap[cur_pos]) {
+            continue;
+        }
+        auto single_map_size = offsets[cur_pos] - offsets[prev_pos];
+        new (map_value) MapValue(single_map_size);

Review Comment:
   it's more efficient to allocate _num_rows MapValue once.



##########
be/src/vec/functions/array/function_array_element.h:
##########
@@ -81,6 +94,79 @@ class FunctionArrayElement : public IFunction {
     }
 
 private:
+    //=========================== map element===========================//
+    ColumnPtr _get_mapped_idx(const ColumnArray& key_column,
+                           const ColumnWithTypeAndName& argument) {
+        if (key_column.get_data().is_column_string()) {
+            return _mapped_key_string(key_column, argument);
+        }
+        return nullptr;

Review Comment:
   add TODO to support other key types



##########
be/src/olap/rowset/segment_v2/column_writer.cpp:
##########
@@ -695,5 +808,120 @@
     return Status::NotSupported("array writer has no data, can not 
finish_current_page");
 }
 
+/// ============================= MapColumnWriter =====================////
+MapColumnWriter::MapColumnWriter(const ColumnWriterOptions& opts, 
std::unique_ptr<Field> field,
+                                     ScalarColumnWriter* null_writer,
+                                     std::unique_ptr<ColumnWriter> key_writer,
+                                     std::unique_ptr<ColumnWriter> 
value_writer)
+        : ColumnWriter(std::move(field), opts.meta->is_nullable()),
+          _key_writer(std::move(key_writer)),
+          _value_writer(std::move(value_writer)),
+          _opts(opts) {
+    if (is_nullable()) {
+        _null_writer.reset(null_writer);
+    }
+}
+
+Status MapColumnWriter::init() {
+    if (is_nullable()) {
+        RETURN_IF_ERROR(_null_writer->init());
+    }
+    RETURN_IF_ERROR(_key_writer->init());
+    RETURN_IF_ERROR(_value_writer->init());
+    return Status::OK();
+}
+
+uint64_t MapColumnWriter::estimate_buffer_size() {
+    size_t estimate =  _key_writer->estimate_buffer_size() +
+                      _value_writer->estimate_buffer_size();
+    if (is_nullable()) {
+        estimate += _null_writer->estimate_buffer_size();
+    }
+    return estimate;
+}
+
+Status MapColumnWriter::finish() {
+    if (is_nullable()) {
+        RETURN_IF_ERROR(_null_writer->finish());
+    }
+    RETURN_IF_ERROR(_key_writer->finish());
+    RETURN_IF_ERROR(_value_writer->finish());
+    return Status::OK();
+}
+
+// todo. make keys and values write
+Status MapColumnWriter::append_data(const uint8_t** ptr, size_t num_rows) {
+    size_t remaining = num_rows;
+    const auto* col_cursor = reinterpret_cast<const MapValue*>(*ptr);
+    while (remaining > 0) {
+        size_t num_written = 1;
+        auto* key_data_ptr = 
const_cast<MapValue*>(col_cursor)->mutable_key_data();
+       const uint8_t* key_ptr = (const uint8_t*)key_data_ptr;
+       RETURN_IF_ERROR(_key_writer->append_data(&key_ptr, 1));
+        auto* val_data_ptr = 
const_cast<MapValue*>(col_cursor)->mutable_value_data();
+       const uint8_t* val_ptr = (const uint8_t*)val_data_ptr;
+       RETURN_IF_ERROR(_value_writer->append_data(&val_ptr, 1));
+        remaining -= num_written;
+        col_cursor += num_written;
+        *ptr += num_written * sizeof(MapValue);
+    }
+
+    if (is_nullable()) {
+        return write_null_column(num_rows, false);
+    }
+    return Status::OK();
+}
+
+Status MapColumnWriter::write_data() {
+    if (is_nullable()) {
+        RETURN_IF_ERROR(_null_writer->write_data());
+    }
+    RETURN_IF_ERROR(_offset_writer->write_data());

Review Comment:
   no _offset_writer any more



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to