You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2022/01/18 02:07:38 UTC

[incubator-doris] branch master updated: [feature](vectorization) Support Vectorized Exec Engine In Doris (#7785)

This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new e1d7233  [feature](vectorization) Support Vectorized Exec Engine In Doris (#7785)
e1d7233 is described below

commit e1d7233e9ca6addf4967c7df10a7c7c5728716d9
Author: HappenLee <ha...@hotmail.com>
AuthorDate: Tue Jan 18 10:07:15 2022 +0800

    [feature](vectorization) Support Vectorized Exec Engine In Doris (#7785)
    
    # Proposed changes
    
    Issue Number: close #6238
    
        Co-authored-by: HappenLee <ha...@hotmail.com>
        Co-authored-by: stdpain <34...@users.noreply.github.com>
        Co-authored-by: Zhengguo Yang <ya...@gmail.com>
        Co-authored-by: wangbo <50...@qq.com>
        Co-authored-by: emmymiao87 <52...@qq.com>
        Co-authored-by: Pxl <95...@qq.com>
        Co-authored-by: zhangstar333 <87...@users.noreply.github.com>
        Co-authored-by: thinker <zc...@qq.com>
        Co-authored-by: Zeno Yang <15...@qq.com>
        Co-authored-by: Wang Shuo <wa...@gmail.com>
        Co-authored-by: zhoubintao <35...@users.noreply.github.com>
        Co-authored-by: Gabriel <ga...@gmail.com>
        Co-authored-by: xinghuayu007 <14...@qq.com>
        Co-authored-by: weizuo93 <we...@apache.org>
        Co-authored-by: yiguolei <gu...@tencent.com>
        Co-authored-by: anneji-dev <85...@users.noreply.github.com>
        Co-authored-by: awakeljw <99...@qq.com>
        Co-authored-by: taberylyang <95...@users.noreply.github.com>
        Co-authored-by: Cui Kaifeng <48...@users.noreply.github.com>
    
    
    ## Problem Summary:
    
    ### 1. Some code from clickhouse
    
    **ClickHouse is an excellent implementation of the vectorized execution engine database,
    so here we have referenced and learned a lot from its excellent implementation in terms of
    data structure and function implementation.
    We are based on ClickHouse v19.16.2.2 and would like to thank the ClickHouse community and developers.**
    
    The following comment has been added to the code from Clickhouse, eg:
    // This file is copied from
    // https://github.com/ClickHouse/ClickHouse/blob/master/src/Interpreters/AggregationCommon.h
    // and modified by Doris
    
    ### 2. Support exec node and query:
    * vaggregation_node
    * vanalytic_eval_node
    * vassert_num_rows_node
    * vblocking_join_node
    * vcross_join_node
    * vempty_set_node
    * ves_http_scan_node
    * vexcept_node
    * vexchange_node
    * vintersect_node
    * vmysql_scan_node
    * vodbc_scan_node
    * volap_scan_node
    * vrepeat_node
    * vschema_scan_node
    * vselect_node
    * vset_operation_node
    * vsort_node
    * vunion_node
    * vhash_join_node
    
    You can run exec engine of SSB/TPCH and 70% TPCDS stand query test set.
    
    ### 3. Data Model
    
    Vec Exec Engine Support **Dup/Agg/Unq** table, Support Block Reader Vectorized.
    Segment Vec is working in process.
    
    ### 4. How to use
    
    1. Set the environment variable `set enable_vectorized_engine = true; `(required)
    2. Set the environment variable `set batch_size = 4096; ` (recommended)
    
    ### 5. Some diff from origin exec engine
    
    https://github.com/doris-vectorized/doris-vectorized/issues/294
    
    ## Checklist(Required)
    
    1. Does it affect the original behavior: (No)
    2. Has unit tests been added: (Yes)
    3. Has document been added or modified: (No)
    4. Does it need to update dependencies: (No)
    5. Are there any changes that cannot be rolled back: (Yes)
---
 be/CMakeLists.txt                                  |   12 +
 be/src/exec/blocking_join_node.cpp                 |    3 +-
 be/src/exec/data_sink.cpp                          |   15 +-
 be/src/exec/data_sink.h                            |   11 +-
 be/src/exec/es/es_scroll_parser.cpp                |  381 +++++-
 be/src/exec/es/es_scroll_parser.h                  |    8 +
 be/src/exec/es_http_scan_node.cpp                  |   15 +-
 be/src/exec/es_http_scan_node.h                    |   45 +-
 be/src/exec/es_http_scanner.h                      |    2 +-
 be/src/exec/exec_node.cpp                          |  160 ++-
 be/src/exec/exec_node.h                            |   13 +
 be/src/exec/mysql_scan_node.h                      |    2 +-
 be/src/exec/odbc_scan_node.cpp                     |   12 +-
 be/src/exec/odbc_scan_node.h                       |   12 +-
 be/src/exec/olap_scan_node.cpp                     |   57 +-
 be/src/exec/olap_scan_node.h                       |    8 +-
 be/src/exec/olap_scanner.cpp                       |    7 +-
 be/src/exec/olap_scanner.h                         |    4 +-
 be/src/exec/partitioned_aggregation_node.cc        |    2 +-
 be/src/exec/repeat_node.h                          |    2 +-
 be/src/exec/scan_node.h                            |    2 +-
 be/src/exec/schema_scan_node.h                     |    2 +-
 be/src/exec/tablet_info.cpp                        |  224 ++++
 be/src/exec/tablet_info.h                          |  100 ++
 be/src/exec/tablet_sink.cpp                        |   72 +-
 be/src/exec/tablet_sink.h                          |    6 +-
 be/src/exec/text_converter.cpp                     |   22 +
 be/src/exec/text_converter.h                       |    7 +-
 be/src/exec/text_converter.hpp                     |  133 +-
 be/src/exprs/CMakeLists.txt                        |    1 -
 be/src/exprs/aggregate_functions.cpp               |   22 +-
 be/src/exprs/math_functions.cpp                    |    6 +-
 be/src/exprs/math_functions.h                      |   14 +-
 be/src/exprs/runtime_filter.cpp                    |   34 +
 be/src/exprs/runtime_filter.h                      |    1 +
 be/src/exprs/runtime_filter_slots.h                |   38 +-
 be/src/exprs/v_string_functions.h                  |  219 ++++
 be/src/olap/block_column_predicate.cpp             |  114 ++
 be/src/olap/block_column_predicate.h               |   26 +
 be/src/olap/bloom_filter_predicate.h               |   40 +-
 be/src/olap/collect_iterator.cpp                   |    2 +-
 be/src/olap/column_predicate.h                     |   15 +
 be/src/olap/comparison_predicate.cpp               |  163 +++
 be/src/olap/comparison_predicate.h                 |    4 +
 be/src/olap/generic_iterators.cpp                  |   62 +-
 be/src/olap/generic_iterators.h                    |    4 +-
 be/src/olap/in_list_predicate.cpp                  |   39 +
 be/src/olap/in_list_predicate.h                    |    7 +-
 be/src/olap/iterators.h                            |    6 +-
 be/src/olap/null_predicate.cpp                     |   43 +
 be/src/olap/null_predicate.h                       |    8 +
 be/src/olap/olap_define.h                          |    3 +-
 be/src/olap/reader.cpp                             |   11 +-
 be/src/olap/reader.h                               |   24 +-
 be/src/olap/row_block2.cpp                         |  230 ++++
 be/src/olap/row_block2.h                           |    5 +
 be/src/olap/rowset/alpha_rowset_reader.h           |    4 +
 be/src/olap/rowset/beta_rowset_reader.cpp          |   46 +-
 be/src/olap/rowset/beta_rowset_reader.h            |    1 +
 be/src/olap/rowset/rowset_reader.h                 |    8 +
 be/src/olap/rowset/segment_v2/binary_dict_page.cpp |   63 +-
 be/src/olap/rowset/segment_v2/binary_dict_page.h   |    9 +
 be/src/olap/rowset/segment_v2/binary_plain_page.h  |   59 +
 be/src/olap/rowset/segment_v2/binary_prefix_page.h |    4 +
 be/src/olap/rowset/segment_v2/bitshuffle_page.h    |   68 +
 be/src/olap/rowset/segment_v2/column_reader.cpp    |  103 ++
 be/src/olap/rowset/segment_v2/column_reader.h      |   20 +
 .../rowset/segment_v2/empty_segment_iterator.cpp   |    6 +-
 .../rowset/segment_v2/empty_segment_iterator.h     |    3 +-
 .../rowset/segment_v2/frame_of_reference_page.h    |    4 +
 be/src/olap/rowset/segment_v2/page_decoder.h       |    5 +
 be/src/olap/rowset/segment_v2/plain_page.h         |    4 +
 be/src/olap/rowset/segment_v2/rle_page.h           |   23 +
 be/src/olap/rowset/segment_v2/segment_iterator.cpp |  363 +++++-
 be/src/olap/rowset/segment_v2/segment_iterator.h   |   32 +-
 be/src/olap/schema.cpp                             |  110 ++
 be/src/olap/schema.h                               |    8 +
 be/src/olap/tablet_schema.cpp                      |   13 +
 be/src/olap/tablet_schema.h                        |    4 +
 be/src/olap/tuple_reader.cpp                       |    2 +-
 be/src/runtime/datetime_value.cpp                  |    2 +
 be/src/runtime/datetime_value.h                    |    6 +-
 be/src/runtime/descriptors.cpp                     |   21 +-
 be/src/runtime/descriptors.h                       |    6 +-
 be/src/runtime/exec_env.h                          |    2 +
 be/src/runtime/exec_env_init.cpp                   |    2 +
 be/src/runtime/fold_constant_executor.cpp          |   94 +-
 be/src/runtime/fold_constant_executor.h            |    9 +-
 be/src/runtime/mysql_result_writer.cpp             |    8 +-
 be/src/runtime/mysql_result_writer.h               |    2 +
 be/src/runtime/plan_fragment_executor.cpp          |   93 +-
 be/src/runtime/plan_fragment_executor.h            |    5 +-
 be/src/runtime/primitive_type.h                    |   77 +-
 be/src/runtime/raw_value.h                         |   56 +
 be/src/runtime/result_sink.cpp                     |    2 +
 be/src/runtime/row_batch.cpp                       |   56 +-
 be/src/runtime/row_batch.h                         |    5 +-
 be/src/runtime/string_value.hpp                    |   25 +-
 be/src/runtime/types.h                             |   58 +
 be/src/service/internal_service.cpp                |    7 +-
 be/src/udf/udf.cpp                                 |    5 +
 be/src/udf/udf.h                                   |    5 +
 be/src/udf/udf_internal.h                          |    5 +
 be/src/udf/udf_ir.cpp                              |   14 +
 be/src/util/binary_cast.hpp                        |   17 +-
 be/src/util/bitmap_value.h                         |    6 +
 be/src/util/brpc_stub_cache.h                      |    4 +-
 be/src/util/runtime_profile.h                      |    5 +-
 be/src/util/static_asserts.cpp                     |    3 +-
 be/src/util/string_parser.hpp                      |   20 +
 be/src/util/url_coding.cpp                         |    4 +
 be/src/vec/CMakeLists.txt                          |  159 +++
 .../vec/aggregate_functions/aggregate_function.h   |  242 ++++
 .../aggregate_functions/aggregate_function_avg.cpp |   68 +
 .../aggregate_functions/aggregate_function_avg.h   |  128 ++
 .../aggregate_function_bitmap.cpp                  |   87 ++
 .../aggregate_function_bitmap.h                    |  175 +++
 .../aggregate_function_combinator.h                |   81 ++
 .../aggregate_function_count.cpp                   |   52 +
 .../aggregate_functions/aggregate_function_count.h |  122 ++
 .../aggregate_function_distinct.cpp                |   96 ++
 .../aggregate_function_distinct.h                  |  224 ++++
 .../aggregate_function_hll_union_agg.cpp           |   51 +
 .../aggregate_function_hll_union_agg.h             |  133 ++
 .../aggregate_function_min_max.cpp                 |   85 ++
 .../aggregate_function_min_max.h                   |  535 ++++++++
 .../aggregate_function_nothing.h                   |   71 ++
 .../aggregate_function_null.cpp                    |   92 ++
 .../aggregate_functions/aggregate_function_null.h  |  294 +++++
 .../aggregate_function_reader.cpp                  |   48 +
 .../aggregate_function_reader.h}                   |   30 +-
 .../aggregate_function_simple_factory.cpp          |   64 +
 .../aggregate_function_simple_factory.h            |  114 ++
 .../aggregate_function_stddev.cpp                  |  101 ++
 .../aggregate_function_stddev.h                    |  285 +++++
 .../aggregate_functions/aggregate_function_sum.cpp |   88 ++
 .../aggregate_functions/aggregate_function_sum.h   |  118 ++
 .../aggregate_function_uniq.cpp                    |   69 ++
 .../aggregate_functions/aggregate_function_uniq.h  |  131 ++
 .../aggregate_function_window.cpp                  |  176 +++
 .../aggregate_function_window.h                    |  434 +++++++
 be/src/vec/aggregate_functions/factory_helpers.h   |   59 +
 be/src/vec/aggregate_functions/helpers.h           |  225 ++++
 .../vec/aggregate_functions/key_holder_helpers.h   |   48 +
 be/src/vec/columns/collator.cpp                    |   97 ++
 .../columns/collator.h}                            |   34 +-
 be/src/vec/columns/column.cpp                      |   57 +
 be/src/vec/columns/column.h                        |  498 ++++++++
 be/src/vec/columns/column_complex.h                |  297 +++++
 be/src/vec/columns/column_const.cpp                |  107 ++
 be/src/vec/columns/column_const.h                  |  178 +++
 be/src/vec/columns/column_decimal.cpp              |  249 ++++
 be/src/vec/columns/column_decimal.h                |  220 ++++
 be/src/vec/columns/column_dummy.h                  |  145 +++
 be/src/vec/columns/column_impl.h                   |   62 +
 .../columns/column_nothing.h}                      |   37 +-
 be/src/vec/columns/column_nullable.cpp             |  453 +++++++
 be/src/vec/columns/column_nullable.h               |  246 ++++
 be/src/vec/columns/column_set.h                    |   52 +
 be/src/vec/columns/column_string.cpp               |  381 ++++++
 be/src/vec/columns/column_string.h                 |  288 +++++
 be/src/vec/columns/column_vector.cpp               |  381 ++++++
 be/src/vec/columns/column_vector.h                 |  296 +++++
 be/src/vec/columns/column_vector_helper.h          |   59 +
 be/src/vec/columns/columns_common.cpp              |  271 ++++
 be/src/vec/columns/columns_common.h                |  121 ++
 .../columns/columns_number.h}                      |   40 +-
 be/src/vec/columns/predicate_column.h              |  447 +++++++
 be/src/vec/common/aggregation_common.h             |  269 ++++
 be/src/vec/common/allocator.h                      |  312 +++++
 .../common/allocator_fwd.h}                        |   26 +-
 be/src/vec/common/arena.h                          |  285 +++++
 be/src/vec/common/arithmetic_overflow.h            |  112 ++
 be/src/vec/common/assert_cast.h                    |   56 +
 be/src/vec/common/bit_cast.h                       |   47 +
 be/src/vec/common/bit_helpers.h                    |   92 ++
 be/src/vec/common/columns_hashing.h                |  242 ++++
 be/src/vec/common/columns_hashing_impl.h           |  324 +++++
 be/src/vec/common/cow.h                            |  439 +++++++
 be/src/vec/common/demangle.cpp                     |   61 +
 .../common/demangle.h}                             |   26 +-
 be/src/vec/common/exception.cpp                    |  202 +++
 be/src/vec/common/exception.h                      |  287 +++++
 be/src/vec/common/field_visitors.h                 |  554 +++++++++
 be/src/vec/common/hash_table/fixed_hash_map.h      |  194 +++
 be/src/vec/common/hash_table/fixed_hash_table.h    |  383 ++++++
 be/src/vec/common/hash_table/hash.h                |  191 +++
 be/src/vec/common/hash_table/hash_map.h            |  240 ++++
 be/src/vec/common/hash_table/hash_set.h            |  105 ++
 be/src/vec/common/hash_table/hash_table.h          |  914 ++++++++++++++
 .../common/hash_table/hash_table_allocator.h}      |   32 +-
 .../vec/common/hash_table/hash_table_key_holder.h  |  139 +++
 be/src/vec/common/int_exp.h                        |  135 ++
 be/src/vec/common/memcmp_small.h                   |  228 ++++
 be/src/vec/common/memcpy_small.h                   |   83 ++
 be/src/vec/common/mremap.h                         |   77 ++
 be/src/vec/common/nan_utils.h                      |   69 ++
 .../common/pod_array.cpp}                          |   23 +-
 be/src/vec/common/pod_array.h                      |  591 +++++++++
 be/src/vec/common/pod_array_fwd.h                  |   53 +
 be/src/vec/common/radix_sort.h                     |  389 ++++++
 be/src/vec/common/sip_hash.h                       |  231 ++++
 be/src/vec/common/string_buffer.hpp                |   93 ++
 be/src/vec/common/string_ref.h                     |  327 +++++
 .../common/string_utils/string_utils.cpp}          |   24 +-
 be/src/vec/common/string_utils/string_utils.h      |  155 +++
 be/src/vec/common/strong_typedef.h                 |   84 ++
 be/src/vec/common/typeid_cast.h                    |   62 +
 be/src/vec/common/uint128.h                        |  237 ++++
 be/src/vec/common/unaligned.h                      |   42 +
 be/src/vec/core/accurate_comparison.h              |  567 +++++++++
 be/src/vec/core/block.cpp                          |  926 ++++++++++++++
 be/src/vec/core/block.h                            |  356 ++++++
 .../core/block_info.cpp}                           |   30 +-
 be/src/vec/core/block_info.h                       |   76 ++
 be/src/vec/core/call_on_type_index.h               |  260 ++++
 .../core/column_numbers.h}                         |   20 +-
 be/src/vec/core/column_with_type_and_name.cpp      |   72 ++
 be/src/vec/core/column_with_type_and_name.h        |   56 +
 .../core/columns_with_type_and_name.h}             |   21 +-
 be/src/vec/core/decimal_comparison.h               |  303 +++++
 be/src/vec/core/field.cpp                          |  193 +++
 be/src/vec/core/field.h                            |  909 ++++++++++++++
 .../core/materialize_block.cpp}                    |   31 +-
 .../core/materialize_block.h}                      |   36 +-
 .../empty_segment_iterator.h => vec/core/names.h}  |   35 +-
 be/src/vec/core/sort_block.cpp                     |  202 +++
 be/src/vec/core/sort_block.h                       |   55 +
 be/src/vec/core/sort_cursor.h                      |  228 ++++
 be/src/vec/core/sort_description.h                 |   80 ++
 be/src/vec/core/types.h                            |  445 +++++++
 be/src/vec/data_types/data_type.cpp                |  217 ++++
 be/src/vec/data_types/data_type.h                  |  402 ++++++
 be/src/vec/data_types/data_type_bitmap.cpp         |  102 ++
 be/src/vec/data_types/data_type_bitmap.h           |   89 ++
 be/src/vec/data_types/data_type_date.cpp           |   66 +
 be/src/vec/data_types/data_type_date.h             |   42 +
 be/src/vec/data_types/data_type_date_time.cpp      |   95 ++
 be/src/vec/data_types/data_type_date_time.h        |   83 ++
 be/src/vec/data_types/data_type_decimal.cpp        |  146 +++
 be/src/vec/data_types/data_type_decimal.h          |  352 ++++++
 be/src/vec/data_types/data_type_factory.hpp        |   87 ++
 .../data_types/data_type_nothing.cpp}              |   30 +-
 be/src/vec/data_types/data_type_nothing.h          |   65 +
 be/src/vec/data_types/data_type_nullable.cpp       |  113 ++
 be/src/vec/data_types/data_type_nullable.h         |   90 ++
 be/src/vec/data_types/data_type_number.h           |   87 ++
 be/src/vec/data_types/data_type_number_base.cpp    |  123 ++
 be/src/vec/data_types/data_type_number_base.h      |   69 ++
 be/src/vec/data_types/data_type_string.cpp         |  123 ++
 be/src/vec/data_types/data_type_string.h           |   61 +
 be/src/vec/data_types/get_least_supertype.cpp      |  322 +++++
 .../data_types/get_least_supertype.h}              |   27 +-
 be/src/vec/data_types/nested_utils.cpp             |   73 ++
 be/src/vec/data_types/nested_utils.h               |   43 +
 be/src/vec/data_types/number_traits.h              |  275 ++++
 be/src/vec/exec/join/join_op.h                     |  143 +++
 be/src/vec/exec/join/vacquire_list.hpp             |   54 +
 be/src/vec/exec/join/vhash_join_node.cpp           | 1062 ++++++++++++++++
 be/src/vec/exec/join/vhash_join_node.h             |  225 ++++
 be/src/vec/exec/vaggregation_node.cpp              | 1102 +++++++++++++++++
 be/src/vec/exec/vaggregation_node.h                |  483 ++++++++
 be/src/vec/exec/vanalytic_eval_node.cpp            |  658 ++++++++++
 be/src/vec/exec/vanalytic_eval_node.h              |  146 +++
 be/src/vec/exec/vassert_num_rows_node.cpp          |   99 ++
 .../exec/vassert_num_rows_node.h}                  |   32 +-
 .../exec/vblocking_join_node.cpp}                  |  104 +-
 be/src/vec/exec/vblocking_join_node.h              |  132 ++
 be/src/vec/exec/vcross_join_node.cpp               |  184 +++
 be/src/vec/exec/vcross_join_node.h                 |   85 ++
 .../exec/vempty_set_node.cpp}                      |   24 +-
 .../exec/vempty_set_node.h}                        |   29 +-
 be/src/vec/exec/ves_http_scan_node.cpp             |  176 +++
 .../exec/ves_http_scan_node.h}                     |   36 +-
 be/src/vec/exec/ves_http_scanner.cpp               |   56 +
 .../exec/ves_http_scanner.h}                       |   33 +-
 be/src/vec/exec/vexcept_node.cpp                   |  112 ++
 .../exec/vexcept_node.h}                           |   28 +-
 be/src/vec/exec/vexchange_node.cpp                 |  104 ++
 be/src/vec/exec/vexchange_node.h                   |   58 +
 be/src/vec/exec/vintersect_node.cpp                |  111 ++
 be/src/vec/exec/vintersect_node.h                  |   49 +
 be/src/vec/exec/vmysql_scan_node.cpp               |  124 ++
 .../exec/vmysql_scan_node.h}                       |   36 +-
 be/src/vec/exec/vodbc_scan_node.cpp                |  130 ++
 .../exec/vodbc_scan_node.h}                        |   23 +-
 be/src/vec/exec/volap_scan_node.cpp                |  559 +++++++++
 be/src/vec/exec/volap_scan_node.h                  |   69 ++
 be/src/vec/exec/volap_scanner.cpp                  |  206 +++
 be/src/vec/exec/volap_scanner.h                    |   55 +
 be/src/vec/exec/vrepeat_node.cpp                   |  244 ++++
 be/src/vec/exec/vrepeat_node.h                     |   56 +
 be/src/vec/exec/vschema_scan_node.cpp              |  263 ++++
 .../exec/vschema_scan_node.h}                      |   37 +-
 be/src/vec/exec/vselect_node.cpp                   |   72 ++
 .../exec/vselect_node.h}                           |   28 +-
 be/src/vec/exec/vset_operation_node.cpp            |  379 ++++++
 be/src/vec/exec/vset_operation_node.h              |  245 ++++
 be/src/vec/exec/vsort_exec_exprs.cpp               |   79 ++
 be/src/vec/exec/vsort_exec_exprs.h                 |   98 ++
 be/src/vec/exec/vsort_node.cpp                     |  256 ++++
 be/src/vec/exec/vsort_node.h                       |   92 ++
 be/src/vec/exec/vunion_node.cpp                    |  279 +++++
 be/src/vec/exec/vunion_node.h                      |  109 ++
 be/src/vec/exprs/vcase_expr.cpp                    |  114 ++
 be/src/vec/exprs/vcase_expr.h                      |   49 +
 be/src/vec/exprs/vcast_expr.cpp                    |   97 ++
 be/src/vec/exprs/vcast_expr.h                      |   53 +
 .../exprs/vcompound_pred.h}                        |   39 +-
 be/src/vec/exprs/vectorized_agg_fn.cpp             |  175 +++
 be/src/vec/exprs/vectorized_agg_fn.h               |  106 ++
 be/src/vec/exprs/vectorized_fn_call.cpp            |  120 ++
 be/src/vec/exprs/vectorized_fn_call.h              |   46 +
 be/src/vec/exprs/vexpr.cpp                         |  343 +++++
 be/src/vec/exprs/vexpr.h                           |  168 +++
 be/src/vec/exprs/vexpr_context.cpp                 |  137 ++
 be/src/vec/exprs/vexpr_context.h                   |   91 ++
 be/src/vec/exprs/vin_predicate.cpp                 |  109 ++
 be/src/vec/exprs/vin_predicate.h                   |   52 +
 be/src/vec/exprs/vinfo_func.cpp                    |   59 +
 .../exprs/vinfo_func.h}                            |   34 +-
 be/src/vec/exprs/vliteral.cpp                      |  138 +++
 .../exprs/vliteral.h}                              |   32 +-
 be/src/vec/exprs/vslot_ref.cpp                     |   75 ++
 be/src/vec/exprs/vslot_ref.h                       |   50 +
 .../functions/cast_type_to_either.h}               |   23 +-
 .../functions/comparison.cpp}                      |   27 +-
 be/src/vec/functions/comparison_equal_for_null.cpp |  125 ++
 .../functions/comparison_equals.cpp}               |   23 +-
 .../functions/comparison_greater.cpp}              |   23 +-
 .../functions/comparison_less.cpp}                 |   23 +-
 be/src/vec/functions/date_time_transforms.h        |  261 ++++
 be/src/vec/functions/divide.cpp                    |   48 +
 be/src/vec/functions/function.cpp                  |  330 +++++
 be/src/vec/functions/function.h                    |  595 +++++++++
 .../vec/functions/function_always_not_nullable.h   |   85 ++
 be/src/vec/functions/function_binary_arithmetic.h  |  719 +++++++++++
 .../function_binary_arithmetic_to_null_type.h      |  247 ++++
 be/src/vec/functions/function_bit.cpp              |   92 ++
 be/src/vec/functions/function_bitmap.cpp           |  471 +++++++
 .../functions/function_case.cpp}                   |   21 +-
 be/src/vec/functions/function_case.h               |  371 ++++++
 .../functions/function_cast.cpp}                   |   25 +-
 be/src/vec/functions/function_cast.h               | 1307 ++++++++++++++++++++
 be/src/vec/functions/function_coalesce.cpp         |  267 ++++
 be/src/vec/functions/function_const.h              |  101 ++
 be/src/vec/functions/function_conv.cpp             |  163 +++
 .../function_date_or_datetime_computation.cpp      |  140 +++
 .../function_date_or_datetime_computation.h        |  488 ++++++++
 .../function_date_or_datetime_to_something.h       |   93 ++
 .../function_date_or_datetime_to_string.cpp}       |   23 +-
 .../function_date_or_datetime_to_string.h          |   66 +
 .../function_datetime_string_to_string.cpp}        |   20 +-
 .../functions/function_datetime_string_to_string.h |   99 ++
 .../functions/function_grouping.cpp}               |   21 +-
 be/src/vec/functions/function_grouping.h           |   90 ++
 be/src/vec/functions/function_hash.cpp             |  254 ++++
 .../functions/function_hash.h}                     |   35 +-
 be/src/vec/functions/function_helpers.cpp          |   99 ++
 be/src/vec/functions/function_helpers.h            |  104 ++
 .../functions/function_ifnull.cpp}                 |   23 +-
 be/src/vec/functions/function_ifnull.h             |  101 ++
 be/src/vec/functions/function_json.cpp             |  369 ++++++
 .../vec/functions/function_math_binary_float64.h   |  248 ++++
 be/src/vec/functions/function_math_unary.h         |  167 +++
 be/src/vec/functions/function_string.cpp           |  809 ++++++++++++
 be/src/vec/functions/function_string.h             | 1145 +++++++++++++++++
 be/src/vec/functions/function_string_to_string.h   |   78 ++
 be/src/vec/functions/function_timestamp.cpp        |  325 +++++
 be/src/vec/functions/function_totype.h             |  428 +++++++
 be/src/vec/functions/function_unary_arithmetic.h   |  157 +++
 be/src/vec/functions/function_utility.cpp          |  118 ++
 be/src/vec/functions/function_variadic_arguments.h |   79 ++
 be/src/vec/functions/functions_comparison.h        |  475 +++++++
 be/src/vec/functions/functions_logical.cpp         |  531 ++++++++
 be/src/vec/functions/functions_logical.h           |  167 +++
 be/src/vec/functions/hll_cardinality.cpp           |   71 ++
 .../functions/hll_empty.cpp}                       |   38 +-
 be/src/vec/functions/hll_hash.cpp                  |  100 ++
 be/src/vec/functions/if.cpp                        |  480 +++++++
 be/src/vec/functions/in.cpp                        |  182 +++
 be/src/vec/functions/int_div.cpp                   |  153 +++
 be/src/vec/functions/int_div.h                     |   56 +
 be/src/vec/functions/is_not_null.cpp               |   76 ++
 be/src/vec/functions/is_null.cpp                   |   77 ++
 be/src/vec/functions/like.cpp                      |  321 +++++
 be/src/vec/functions/like.h                        |  155 +++
 be/src/vec/functions/math.cpp                      |  475 +++++++
 be/src/vec/functions/minus.cpp                     |   56 +
 be/src/vec/functions/modulo.cpp                    |  159 +++
 be/src/vec/functions/multiply.cpp                  |   56 +
 be/src/vec/functions/nullif.cpp                    |  155 +++
 be/src/vec/functions/plus.cpp                      |   57 +
 be/src/vec/functions/random.cpp                    |  109 ++
 be/src/vec/functions/simple_function_factory.h     |  190 +++
 be/src/vec/functions/time_of_function.cpp          |   37 +
 be/src/vec/functions/to_time_function.cpp          |   54 +
 be/src/vec/io/io_helper.h                          |  357 ++++++
 .../io/reader_buffer.h}                            |   36 +-
 be/src/vec/io/var_int.h                            |  176 +++
 be/src/vec/olap/block_reader.cpp                   |  366 ++++++
 be/src/vec/olap/block_reader.h                     |  119 ++
 be/src/vec/olap/vcollect_iterator.cpp              |  380 ++++++
 be/src/vec/olap/vcollect_iterator.h                |  193 +++
 be/src/vec/olap/vgeneric_iterators.cpp             |  443 +++++++
 .../olap/vgeneric_iterators.h}                     |    8 +-
 be/src/vec/runtime/vdata_stream_mgr.cpp            |  194 +++
 be/src/vec/runtime/vdata_stream_mgr.h              |   91 ++
 be/src/vec/runtime/vdata_stream_recvr.cpp          |  364 ++++++
 be/src/vec/runtime/vdata_stream_recvr.h            |  188 +++
 .../runtime/vdatetime_value.cpp}                   |  245 ++--
 .../runtime/vdatetime_value.h}                     |  163 ++-
 be/src/vec/runtime/vpartition_info.cpp             |   56 +
 be/src/vec/runtime/vpartition_info.h               |   59 +
 be/src/vec/runtime/vsorted_run_merger.cpp          |  156 +++
 be/src/vec/runtime/vsorted_run_merger.h            |   91 ++
 be/src/vec/sink/mysql_result_writer.cpp            |  349 ++++++
 be/src/{runtime => vec/sink}/mysql_result_writer.h |   48 +-
 be/src/{runtime => vec/sink}/result_sink.cpp       |   85 +-
 be/src/vec/sink/result_sink.h                      |   79 ++
 .../sink/result_writer.h}                          |   23 +-
 be/src/vec/sink/vdata_stream_sender.cpp            |  546 ++++++++
 be/src/vec/sink/vdata_stream_sender.h              |  297 +++++
 be/src/vec/sink/vtabet_sink.cpp                    |  276 +++++
 be/src/vec/sink/vtablet_sink.h                     |   65 +
 be/src/vec/utils/util.hpp                          |   79 ++
 be/test/exprs/string_functions_test.cpp            |   43 +-
 .../olap/bloom_filter_column_predicate_test.cpp    |   36 +
 be/test/olap/column_reader_test.cpp                |  108 ++
 be/test/olap/generic_iterators_test.cpp            |    6 +-
 be/test/olap/null_predicate_test.cpp               |  144 +++
 .../rowset/segment_v2/binary_dict_page_test.cpp    |    2 +
 .../segment_v2/column_reader_writer_test.cpp       |  122 ++
 be/test/tools/benchmark_tool.cpp                   |    2 +-
 be/test/vec/aggregate_functions/CMakeLists.txt     |   23 +
 be/test/vec/aggregate_functions/agg_test.cpp       |   61 +
 be/test/vec/core/CMakeLists.txt                    |   23 +
 be/test/vec/core/block_test.cpp                    |  309 +++++
 be/test/vec/core/column_complex_test.cpp           |   52 +
 be/test/vec/exec/CMakeLists.txt                    |   21 +
 be/test/vec/exec/vgeneric_iterators_test.cpp       |  207 ++++
 be/test/vec/exprs/CMakeLists.txt                   |   22 +
 be/test/vec/exprs/vexpr_test.cpp                   |  357 ++++++
 be/test/vec/function/CMakeLists.txt                |   30 +
 be/test/vec/function/function_arithmetic_test.cpp  |  125 ++
 be/test/vec/function/function_bitmap_test.cpp      |  115 ++
 be/test/vec/function/function_comparison_test.cpp  |  150 +++
 be/test/vec/function/function_hash_test.cpp        |   96 ++
 be/test/vec/function/function_ifnull_test.cpp      |   72 ++
 be/test/vec/function/function_like_test.cpp        |  115 ++
 be/test/vec/function/function_math_test.cpp        |  499 ++++++++
 be/test/vec/function/function_nullif_test.cpp      |   64 +
 be/test/vec/function/function_string_test.cpp      |  721 +++++++++++
 be/test/vec/function/function_test_util.h          |  374 ++++++
 be/test/vec/function/function_time_test.cpp        |  501 ++++++++
 be/test/vec/runtime/CMakeLists.txt                 |   22 +
 be/test/vec/runtime/vdata_stream_test.cpp          |  178 +++
 docs/.vuepress/sidebar/en.js                       |    6 +
 docs/.vuepress/sidebar/zh-CN.js                    |    6 +
 .../sql-functions/math-functions/conv.md           |   60 +
 .../sql-functions/string-functions/coalesce.md     |   62 +
 .../sql-functions/math-functions/conv.md           |   60 +
 .../sql-functions/string-functions/coalesce.md     |   63 +
 .../org/apache/doris/analysis/AnalyticExpr.java    |    6 +-
 .../java/org/apache/doris/analysis/Analyzer.java   |   25 +
 .../org/apache/doris/analysis/ArithmeticExpr.java  |  125 +-
 .../org/apache/doris/analysis/BinaryPredicate.java |    2 +
 .../java/org/apache/doris/analysis/CastExpr.java   |    7 +
 .../apache/doris/analysis/FunctionCallExpr.java    |    2 +-
 .../org/apache/doris/analysis/InPredicate.java     |    9 +-
 .../org/apache/doris/analysis/LikePredicate.java   |    5 +-
 .../java/org/apache/doris/analysis/SelectStmt.java |    5 +
 .../apache/doris/analysis/SetOperationStmt.java    |    5 +-
 .../java/org/apache/doris/analysis/TableRef.java   |    6 +
 .../apache/doris/catalog/AggregateFunction.java    |   21 +-
 .../java/org/apache/doris/catalog/Catalog.java     |   17 +-
 .../java/org/apache/doris/catalog/FunctionSet.java |  145 ++-
 .../main/java/org/apache/doris/catalog/Type.java   |   25 +
 .../doris/common/profile/PlanTreeBuilder.java      |    1 +
 .../doris/common/profile/ProfileTreeBuilder.java   |    6 +
 .../org/apache/doris/planner/AnalyticPlanner.java  |    1 +
 .../org/apache/doris/planner/ExchangeNode.java     |    1 +
 .../org/apache/doris/planner/HashJoinNode.java     |   47 +-
 .../org/apache/doris/planner/OlapScanNode.java     |    1 -
 .../java/org/apache/doris/planner/PlanNode.java    |    9 +-
 .../java/org/apache/doris/planner/Planner.java     |    1 +
 .../apache/doris/planner/SingleNodePlanner.java    |   14 +-
 .../main/java/org/apache/doris/qe/Coordinator.java |    1 -
 .../java/org/apache/doris/rewrite/FEFunctions.java |   64 +-
 .../apache/doris/rewrite/FoldConstantsRule.java    |    6 +-
 .../java/org/apache/doris/qe/CoordinatorTest.java  |    9 +-
 gensrc/proto/palo_internal_service.proto           |   46 +
 gensrc/script/doris_builtins_functions.py          |  333 +++--
 gensrc/script/gen_build_version.sh                 |    2 +-
 gensrc/script/gen_builtins_functions.py            |    5 +
 gensrc/thrift/DataSinks.thrift                     |    2 -
 gensrc/thrift/PlanNodes.thrift                     |    5 +
 run-be-ut.sh                                       |   26 +-
 498 files changed, 66173 insertions(+), 1493 deletions(-)

diff --git a/be/CMakeLists.txt b/be/CMakeLists.txt
index 24f28b1..1bd3e49 100644
--- a/be/CMakeLists.txt
+++ b/be/CMakeLists.txt
@@ -469,6 +469,7 @@ set(DORIS_LINK_LIBS
     DorisGen
     Webserver
     Geo
+    Vec
     Plugin
     ${WL_END_GROUP}
 )
@@ -653,6 +654,7 @@ endif()
 
 add_subdirectory(${SRC_DIR}/util)
 add_subdirectory(${SRC_DIR}/plugin)
+add_subdirectory(${SRC_DIR}/vec)
 
 # Utility CMake function to make specifying tests and benchmarks less verbose
 FUNCTION(ADD_BE_TEST TEST_NAME)
@@ -705,6 +707,11 @@ if (${MAKE_TEST} STREQUAL "ON")
     add_subdirectory(${TEST_DIR}/runtime)
     add_subdirectory(${TEST_DIR}/udf)
     add_subdirectory(${TEST_DIR}/util)
+    add_subdirectory(${TEST_DIR}/vec/core)
+    add_subdirectory(${TEST_DIR}/vec/exprs)
+    add_subdirectory(${TEST_DIR}/vec/function)
+    add_subdirectory(${TEST_DIR}/vec/runtime)
+    add_subdirectory(${TEST_DIR}/vec/aggregate_functions)
     add_subdirectory(${TEST_DIR}/plugin)
     add_subdirectory(${TEST_DIR}/plugin/example)
     add_subdirectory(${TEST_DIR}/tools)
@@ -728,3 +735,8 @@ install(FILES
     ${BASE_DIR}/../conf/odbcinst.ini
     DESTINATION ${OUTPUT_DIR}/conf)
 
+
+get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
+foreach(dir ${dirs})
+  message(STATUS "dir='${dir}'")
+  endforeach()
diff --git a/be/src/exec/blocking_join_node.cpp b/be/src/exec/blocking_join_node.cpp
index da97701..ba13786 100644
--- a/be/src/exec/blocking_join_node.cpp
+++ b/be/src/exec/blocking_join_node.cpp
@@ -30,7 +30,8 @@ namespace doris {
 BlockingJoinNode::BlockingJoinNode(const std::string& node_name, const TJoinOp::type join_op,
                                    ObjectPool* pool, const TPlanNode& tnode,
                                    const DescriptorTbl& descs)
-        : ExecNode(pool, tnode, descs), _node_name(node_name), _join_op(join_op) {}
+        : ExecNode(pool, tnode, descs), _node_name(node_name), _join_op(join_op),
+          _left_side_eos(false) {}
 
 Status BlockingJoinNode::init(const TPlanNode& tnode, RuntimeState* state) {
     return ExecNode::init(tnode, state);
diff --git a/be/src/exec/data_sink.cpp b/be/src/exec/data_sink.cpp
index aefa087..cf06f09 100644
--- a/be/src/exec/data_sink.cpp
+++ b/be/src/exec/data_sink.cpp
@@ -35,7 +35,10 @@
 #include "runtime/result_file_sink.h"
 #include "runtime/result_sink.h"
 #include "runtime/runtime_state.h"
-#include "util/logging.h"
+
+#include "vec/sink/result_sink.h"
+#include "vec/sink/vdata_stream_sender.h"
+#include "vec/sink/vtablet_sink.h"
 
 namespace doris {
 
@@ -57,6 +60,9 @@ Status DataSink::create_data_sink(ObjectPool* pool, const TDataSink& thrift_sink
                         : false;
         // TODO: figure out good buffer size based on size of output row
         if (is_vec) {
+            tmp_sink = new doris::vectorized::VDataStreamSender(
+                    pool, params.sender_id, row_desc, thrift_sink.stream_sink, params.destinations,
+                    16 * 1024, send_query_statistics_with_every_batch);
         } else {
             tmp_sink = new DataStreamSender(pool, params.sender_id, row_desc,
                                             thrift_sink.stream_sink, params.destinations, 16 * 1024,
@@ -73,6 +79,7 @@ Status DataSink::create_data_sink(ObjectPool* pool, const TDataSink& thrift_sink
 
         // TODO: figure out good buffer size based on size of output row
         if (is_vec) {
+            tmp_sink = new doris::vectorized::VResultSink(row_desc, output_exprs, thrift_sink.result_sink, 4096);
         } else {
             tmp_sink = new ResultSink(row_desc, output_exprs, thrift_sink.result_sink, 1024);
         }
@@ -149,7 +156,11 @@ Status DataSink::create_data_sink(ObjectPool* pool, const TDataSink& thrift_sink
     case TDataSinkType::OLAP_TABLE_SINK: {
         Status status;
         DCHECK(thrift_sink.__isset.olap_table_sink);
-        sink->reset(new stream_load::OlapTableSink(pool, row_desc, output_exprs, &status));
+        if (is_vec) {
+            sink->reset(new stream_load::VOlapTableSink(pool, row_desc, output_exprs, &status));
+        } else {
+            sink->reset(new stream_load::OlapTableSink(pool, row_desc, output_exprs, &status));
+        }
         RETURN_IF_ERROR(status);
         break;
     }
diff --git a/be/src/exec/data_sink.h b/be/src/exec/data_sink.h
index 30f5580..fcec10a 100644
--- a/be/src/exec/data_sink.h
+++ b/be/src/exec/data_sink.h
@@ -33,11 +33,13 @@ class ObjectPool;
 class RowBatch;
 class RuntimeProfile;
 class RuntimeState;
-class TPlanExecRequest;
-class TPlanExecParams;
 class TPlanFragmentExecParams;
 class RowDescriptor;
 
+namespace vectorized {
+class Block;
+}
+
 // Superclass of all data sinks.
 class DataSink {
 public:
@@ -56,8 +58,11 @@ public:
     // Send a row batch into this sink.
     // eos should be true when the last batch is passed to send()
     virtual Status send(RuntimeState* state, RowBatch* batch) = 0;
-    // virtual Status send(RuntimeState* state, RowBatch* batch, bool eos) = 0;
 
+    // Send a Block into this sink.
+    virtual Status send(RuntimeState* state, vectorized::Block* block) {
+        return Status::NotSupported("Not support send block");
+    };
     // Releases all resources that were allocated in prepare()/send().
     // Further send() calls are illegal after calling close().
     // It must be okay to call this multiple times. Subsequent calls should
diff --git a/be/src/exec/es/es_scroll_parser.cpp b/be/src/exec/es/es_scroll_parser.cpp
index 396c086..86cd16a 100644
--- a/be/src/exec/es/es_scroll_parser.cpp
+++ b/be/src/exec/es/es_scroll_parser.cpp
@@ -31,6 +31,7 @@
 #include "runtime/mem_pool.h"
 #include "runtime/mem_tracker.h"
 #include "util/string_parser.hpp"
+#include "vec/runtime/vdatetime_value.h"
 
 namespace doris {
 
@@ -79,6 +80,8 @@ static const std::string ERROR_MEM_LIMIT_EXCEEDED =
 static const std::string ERROR_COL_DATA_IS_ARRAY =
         "Data source returned an array for the type $0"
         "based on column metadata.";
+static const std::string INVALID_NULL_VALUE =
+        "Invalid null value occurs: Non-null column `$0` contains NULL";
 
 #define RETURN_ERROR_IF_COL_IS_ARRAY(col, type)                              \
     do {                                                                     \
@@ -169,7 +172,7 @@ static Status get_int_value(const rapidjson::Value& col, PrimitiveType type, voi
 template <typename T>
 static Status get_float_value(const rapidjson::Value& col, PrimitiveType type, void* slot,
                               bool pure_doc_value) {
-    DCHECK(sizeof(T) == 4 || sizeof(T) == 8);
+    static_assert(sizeof(T) == 4 || sizeof(T) == 8);
     if (col.IsNumber()) {
         *reinterpret_cast<T*>(slot) = (T)(sizeof(T) == 4 ? col.GetFloat() : col.GetDouble());
         return Status::OK();
@@ -193,6 +196,68 @@ static Status get_float_value(const rapidjson::Value& col, PrimitiveType type, v
     return Status::OK();
 }
 
+template <typename T>
+static Status insert_float_value(const rapidjson::Value& col, PrimitiveType type,
+                                 vectorized::IColumn* col_ptr, bool pure_doc_value,
+                                 bool nullable) {
+    static_assert(sizeof(T) == 4 || sizeof(T) == 8);
+    if (col.IsNumber() && nullable) {
+        T value = (T)(sizeof(T) == 4 ? col.GetFloat() : col.GetDouble());
+        col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&value)), 0);
+        return Status::OK();
+    }
+
+    if (pure_doc_value && col.IsArray() && nullable) {
+        T value = (T)(sizeof(T) == 4 ? col[0].GetFloat() : col[0].GetDouble());
+        col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&value)), 0);
+        return Status::OK();
+    }
+
+    RETURN_ERROR_IF_COL_IS_ARRAY(col, type);
+    RETURN_ERROR_IF_COL_IS_NOT_STRING(col, type);
+
+    StringParser::ParseResult result;
+    const std::string& val = col.GetString();
+    size_t len = col.GetStringLength();
+    T v = StringParser::string_to_float<T>(val.c_str(), len, &result);
+    RETURN_ERROR_IF_PARSING_FAILED(result, col, type);
+
+    col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&v)), 0);
+
+    return Status::OK();
+}
+
+template <typename T>
+static Status insert_int_value(const rapidjson::Value& col, PrimitiveType type,
+                               vectorized::IColumn* col_ptr, bool pure_doc_value,
+                               bool nullable) {
+    if (col.IsNumber()) {
+        T value = (T)(sizeof(T) < 8 ? col.GetInt() : col.GetInt64());
+        col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&value)), 0);
+        return Status::OK();
+    }
+
+    if (pure_doc_value && col.IsArray()) {
+        RETURN_ERROR_IF_COL_IS_NOT_NUMBER(col[0], type);
+        T value = (T)(sizeof(T) < 8 ? col[0].GetInt() : col[0].GetInt64());
+        col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&value)), 0);
+        return Status::OK();
+    }
+
+    RETURN_ERROR_IF_COL_IS_ARRAY(col, type);
+    RETURN_ERROR_IF_COL_IS_NOT_STRING(col, type);
+
+    StringParser::ParseResult result;
+    const std::string& val = col.GetString();
+    size_t len = col.GetStringLength();
+    T v = StringParser::string_to_int<T>(val.c_str(), len, &result);
+    RETURN_ERROR_IF_PARSING_FAILED(result, col, type);
+
+    col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&v)), 0);
+
+    return Status::OK();
+}
+
 ScrollParser::ScrollParser(bool doc_value_mode)
         : _scroll_id(""), _size(0), _line_index(0), _doc_value_mode(doc_value_mode) {}
 
@@ -426,22 +491,53 @@ Status ScrollParser::fill_tuple(const TupleDescriptor* tuple_desc, Tuple* tuple,
                 *reinterpret_cast<int8_t*>(slot) = col.GetInt();
                 break;
             }
-            if (pure_doc_value && col.IsArray()) {
+
+            bool is_nested_str = false;
+            if (pure_doc_value && col.IsArray() && col[0].IsBool()) {
                 *reinterpret_cast<int8_t*>(slot) = col[0].GetBool();
                 break;
+            } else if (pure_doc_value && col.IsArray() && col[0].IsString()) {
+                is_nested_str = true;
+            } else if (pure_doc_value && col.IsArray()) {
+                return Status::InternalError(
+                        strings::Substitute(ERROR_INVALID_COL_DATA, "BOOLEAN"));
             }
 
-            RETURN_ERROR_IF_COL_IS_ARRAY(col, type);
-            RETURN_ERROR_IF_COL_IS_NOT_STRING(col, type);
-
-            const std::string& val = col.GetString();
-            size_t val_size = col.GetStringLength();
+            const rapidjson::Value& str_col = is_nested_str? col[0]: col;
+            const std::string& val = str_col.GetString();
+            size_t val_size = str_col.GetStringLength();
             StringParser::ParseResult result;
             bool b = StringParser::string_to_bool(val.c_str(), val_size, &result);
-            RETURN_ERROR_IF_PARSING_FAILED(result, col, type);
+            RETURN_ERROR_IF_PARSING_FAILED(result, str_col, type);
             *reinterpret_cast<int8_t*>(slot) = b;
             break;
         }
+        case TYPE_DECIMALV2: {
+            DecimalV2Value data;
+
+            if (col.IsDouble()) {
+                data.assign_from_double(col.GetDouble());
+            } else {
+                std::string val;
+                if (pure_doc_value) {
+                    if (!col[0].IsString()) {
+                        val = json_value_to_string(col[0]);
+                    } else {
+                        val = col[0].GetString();
+                    }
+                } else {
+                    RETURN_ERROR_IF_COL_IS_ARRAY(col, type);
+                    if (!col.IsString()) {
+                        val = json_value_to_string(col);
+                    } else {
+                        val = col.GetString();
+                    }
+                }
+                data.parse_from_str(val.data(), val.length());
+            }
+            reinterpret_cast<DecimalV2Value*>(slot)->set_value(data.value());
+            break;
+        }
 
         case TYPE_DATE:
         case TYPE_DATETIME: {
@@ -482,6 +578,235 @@ Status ScrollParser::fill_tuple(const TupleDescriptor* tuple_desc, Tuple* tuple,
     return Status::OK();
 }
 
+Status ScrollParser::fill_columns(const TupleDescriptor* tuple_desc,
+                                  std::vector<vectorized::MutableColumnPtr>& columns,
+                                  MemPool* tuple_pool, bool* line_eof,
+                                  const std::map<std::string, std::string>& docvalue_context) {
+    *line_eof = true;
+
+    if (_size <= 0 || _line_index >= _size) {
+        return Status::OK();
+    }
+
+    const rapidjson::Value& obj = _inner_hits_node[_line_index++];
+    bool pure_doc_value = false;
+    if (obj.HasMember("fields")) {
+        pure_doc_value = true;
+    }
+    const rapidjson::Value& line = obj.HasMember(FIELD_SOURCE) ? obj[FIELD_SOURCE] : obj["fields"];
+
+    for (int i = 0; i < tuple_desc->slots().size(); ++i) {
+        const SlotDescriptor* slot_desc = tuple_desc->slots()[i];
+        auto col_ptr = columns[i].get();
+
+        if (!slot_desc->is_materialized()) {
+            continue;
+        }
+        if (slot_desc->col_name() == FIELD_ID) {
+            // actually this branch will not be reached, this is guaranteed by Doris FE.
+            if (pure_doc_value) {
+                std::stringstream ss;
+                ss << "obtain `_id` is not supported in doc_values mode";
+                return Status::RuntimeError(ss.str());
+            }
+            // obj[FIELD_ID] must not be NULL
+            std::string _id = obj[FIELD_ID].GetString();
+            size_t len = _id.length();
+
+            col_ptr->insert_data(const_cast<const char*>(_id.data()), len);
+            continue;
+        }
+
+        const char* col_name = pure_doc_value ? docvalue_context.at(slot_desc->col_name()).c_str()
+                                              : slot_desc->col_name().c_str();
+
+        rapidjson::Value::ConstMemberIterator itr = line.FindMember(col_name);
+        if (itr == line.MemberEnd() && slot_desc->is_nullable()) {
+            auto nullable_column = reinterpret_cast<vectorized::ColumnNullable*>(col_ptr);
+            nullable_column->insert_data(nullptr, 0);
+            continue;
+        } else if (itr == line.MemberEnd() && !slot_desc->is_nullable()) {
+            std::string details = strings::Substitute(INVALID_NULL_VALUE, col_name);
+            return Status::RuntimeError(details);
+        }
+
+        const rapidjson::Value& col = line[col_name];
+
+        PrimitiveType type = slot_desc->type().type;
+
+        // when the column value is null, the subsequent type casting will report an error
+        if (col.IsNull() && slot_desc->is_nullable()) {
+            col_ptr->insert_data(nullptr, 0);
+            continue;
+        } else if (col.IsNull() && !slot_desc->is_nullable()) {
+            std::string details = strings::Substitute(INVALID_NULL_VALUE, col_name);
+            return Status::RuntimeError(details);
+        }
+        switch (type) {
+            case TYPE_CHAR:
+            case TYPE_VARCHAR:
+            case TYPE_STRING: {
+                // sometimes elasticsearch user post some not-string value to Elasticsearch Index.
+                // because of reading value from _source, we can not process all json type and then just transfer the value to original string representation
+                // this may be a tricky, but we can workaround this issue
+                std::string val;
+                if (pure_doc_value) {
+                    if (!col[0].IsString()) {
+                        val = json_value_to_string(col[0]);
+                    } else {
+                        val = col[0].GetString();
+                    }
+                } else {
+                    RETURN_ERROR_IF_COL_IS_ARRAY(col, type);
+                    if (!col.IsString()) {
+                        val = json_value_to_string(col);
+                    } else {
+                        val = col.GetString();
+                    }
+                }
+                size_t val_size = val.length();
+                col_ptr->insert_data(
+                        const_cast<const char*>(val.data()), val_size);
+                break;
+            }
+
+            case TYPE_TINYINT: {
+                insert_int_value<int8_t>(col, type, col_ptr, pure_doc_value, slot_desc->is_nullable());
+                break;
+            }
+
+            case TYPE_SMALLINT: {
+                insert_int_value<int16_t>(col, type, col_ptr, pure_doc_value, slot_desc->is_nullable());
+                break;
+            }
+
+            case TYPE_INT: {
+                insert_int_value<int32>(col, type, col_ptr, pure_doc_value, slot_desc->is_nullable());
+                break;
+            }
+
+            case TYPE_BIGINT: {
+                insert_int_value<int64_t>(col, type, col_ptr, pure_doc_value, slot_desc->is_nullable());
+                break;
+            }
+
+            case TYPE_LARGEINT: {
+                insert_int_value<__int128>(col, type, col_ptr, pure_doc_value, slot_desc->is_nullable());
+                break;
+            }
+
+            case TYPE_DOUBLE: {
+                insert_float_value<double>(col, type, col_ptr, pure_doc_value, slot_desc->is_nullable());
+                break;
+            }
+
+            case TYPE_FLOAT: {
+                insert_float_value<float>(col, type, col_ptr, pure_doc_value, slot_desc->is_nullable());
+                break;
+            }
+
+            case TYPE_BOOLEAN: {
+                if (col.IsBool()) {
+                    int8_t val = col.GetBool();
+                    col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&val)), 0);
+                    break;
+                }
+
+                if (col.IsNumber()) {
+                    int8_t val = col.GetInt();
+                    col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&val)), 0);
+                    break;
+                }
+
+                bool is_nested_str = false;
+                if (pure_doc_value && col.IsArray() && col[0].IsBool()) {
+                    int8_t val = col[0].GetBool();
+                    col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&val)), 0);
+                    break;
+                } else if (pure_doc_value && col.IsArray() && col[0].IsString()) {
+                    is_nested_str = true;
+                } else if (pure_doc_value && col.IsArray()) {
+                    return Status::InternalError(
+                            strings::Substitute(ERROR_INVALID_COL_DATA, "BOOLEAN"));
+                }
+
+                const rapidjson::Value& str_col = is_nested_str? col[0]: col;
+
+                const std::string& val = str_col.GetString();
+                size_t val_size = str_col.GetStringLength();
+                StringParser::ParseResult result;
+                bool b = StringParser::string_to_bool(val.c_str(), val_size, &result);
+                RETURN_ERROR_IF_PARSING_FAILED(result, str_col, type);
+                col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&b)), 0);
+                break;
+            }
+            case TYPE_DECIMALV2: {
+                DecimalV2Value data;
+
+                if (col.IsDouble()) {
+                    data.assign_from_double(col.GetDouble());
+                } else {
+                    std::string val;
+                    if (pure_doc_value) {
+                        if (!col[0].IsString()) {
+                            val = json_value_to_string(col[0]);
+                        } else {
+                            val = col[0].GetString();
+                        }
+                    } else {
+                        RETURN_ERROR_IF_COL_IS_ARRAY(col, type);
+                        if (!col.IsString()) {
+                            val = json_value_to_string(col);
+                        } else {
+                            val = col.GetString();
+                        }
+                    }
+                    data.parse_from_str(val.data(), val.length());
+                }
+                col_ptr->insert_data(
+                        const_cast<const char*>(reinterpret_cast<char*>(&data)), 0);
+                break;
+            }
+
+            case TYPE_DATE:
+            case TYPE_DATETIME: {
+                // this would happend just only when `enable_docvalue_scan = false`, and field has timestamp format date from _source
+                if (col.IsNumber()) {
+                    // ES process date/datetime field would use millisecond timestamp for index or docvalue
+                    // processing date type field, if a number is encountered, Doris On ES will force it to be processed according to ms
+                    // Doris On ES needs to be consistent with ES, so just divided by 1000 because the unit for from_unixtime is seconds
+                    RETURN_IF_ERROR(fill_date_col_with_timestamp(col_ptr, col, type));
+                } else if (col.IsArray() && pure_doc_value) {
+                    // this would happened just only when `enable_docvalue_scan = true`
+                    // ES add default format for all field after ES 6.4, if we not provided format for `date` field ES would impose
+                    // a standard date-format for date field as `2020-06-16T00:00:00.000Z`
+                    // At present, we just process this string format date. After some PR were merged into Doris, we would impose `epoch_mills` for
+                    // date field's docvalue
+                    if (col[0].IsString()) {
+                        RETURN_IF_ERROR(fill_date_col_with_strval(col_ptr, col[0], type));
+                        break;
+                    }
+                    // ES would return millisecond timestamp for date field, divided by 1000 because the unit for from_unixtime is seconds
+                    RETURN_IF_ERROR(fill_date_col_with_timestamp(col_ptr, col, type));
+                } else {
+                    // this would happened just only when `enable_docvalue_scan = false`, and field has string format date from _source
+                    RETURN_ERROR_IF_COL_IS_ARRAY(col, type);
+                    RETURN_ERROR_IF_COL_IS_NOT_STRING(col, type);
+                    RETURN_IF_ERROR(fill_date_col_with_strval(col_ptr, col, type));
+                }
+                break;
+            }
+            default: {
+                DCHECK(false);
+                break;
+            }
+        }
+    }
+
+    *line_eof = false;
+    return Status::OK();
+}
+
 Status ScrollParser::fill_date_slot_with_strval(void* slot, const rapidjson::Value& col,
                                                 PrimitiveType type) {
     DateTimeValue* ts_slot = reinterpret_cast<DateTimeValue*>(slot);
@@ -511,4 +836,44 @@ Status ScrollParser::fill_date_slot_with_timestamp(void* slot, const rapidjson::
     return Status::OK();
 }
 
+Status ScrollParser::fill_date_col_with_strval(vectorized::IColumn* col_ptr,
+                                               const rapidjson::Value& col, PrimitiveType type) {
+    vectorized::VecDateTimeValue dt_val;
+    const std::string& val = col.GetString();
+    size_t val_size = col.GetStringLength();
+    if (!dt_val.from_date_str(val.c_str(), val_size)) {
+        RETURN_ERROR_IF_CAST_FORMAT_ERROR(col, type);
+    }
+    if (type == TYPE_DATE) {
+        dt_val.cast_to_date();
+    } else {
+        dt_val.to_datetime();
+    }
+
+    auto date_packed_int = binary_cast<doris::vectorized::VecDateTimeValue, int64_t>(
+            *reinterpret_cast<vectorized::VecDateTimeValue*>(&dt_val));
+    col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&date_packed_int)), 0);
+    return Status::OK();
+}
+
+Status ScrollParser::fill_date_col_with_timestamp(vectorized::IColumn* col_ptr,
+                                                  const rapidjson::Value& col, PrimitiveType type) {
+    vectorized::VecDateTimeValue dt_val;
+    if (!dt_val.from_unixtime(col.GetInt64() / 1000, "+08:00")) {
+        RETURN_ERROR_IF_CAST_FORMAT_ERROR(col, type);
+    }
+    if (type == TYPE_DATE) {
+        reinterpret_cast<vectorized::VecDateTimeValue*>(&dt_val)->cast_to_date();
+    } else {
+        reinterpret_cast<vectorized::VecDateTimeValue*>(&dt_val)->set_type(TIME_DATETIME);
+    }
+
+    auto date_packed_int = binary_cast<doris::vectorized::VecDateTimeValue, int64_t>(
+            *reinterpret_cast<vectorized::VecDateTimeValue*>(&dt_val));
+    col_ptr->insert_data(const_cast<const char*>(reinterpret_cast<char*>(&date_packed_int)), 0);
+
+    return Status::OK();
+}
+
+
 } // namespace doris
diff --git a/be/src/exec/es/es_scroll_parser.h b/be/src/exec/es/es_scroll_parser.h
index f2ff855..30eabaf 100644
--- a/be/src/exec/es/es_scroll_parser.h
+++ b/be/src/exec/es/es_scroll_parser.h
@@ -22,6 +22,7 @@
 #include "rapidjson/document.h"
 #include "runtime/descriptors.h"
 #include "runtime/tuple.h"
+#include "vec/core/block.h"
 
 namespace doris {
 
@@ -35,6 +36,9 @@ public:
     Status parse(const std::string& scroll_result, bool exactly_once = false);
     Status fill_tuple(const TupleDescriptor* _tuple_desc, Tuple* tuple, MemPool* mem_pool,
                       bool* line_eof, const std::map<std::string, std::string>& docvalue_context);
+    Status fill_columns(const TupleDescriptor* _tuple_desc,
+                        std::vector<vectorized::MutableColumnPtr>& columns, MemPool* mem_pool,
+                        bool* line_eof, const std::map<std::string, std::string>& docvalue_context);
 
     const std::string& get_scroll_id();
     int get_size();
@@ -44,9 +48,13 @@ private:
     // type is used for distinguish date and datetime
     // fill date slot with string format date
     Status fill_date_slot_with_strval(void* slot, const rapidjson::Value& col, PrimitiveType type);
+    Status fill_date_col_with_strval(vectorized::IColumn* col_ptr, const rapidjson::Value& col,
+                                     PrimitiveType type);
     // fill date slot with timestamp
     Status fill_date_slot_with_timestamp(void* slot, const rapidjson::Value& col,
                                          PrimitiveType type);
+    Status fill_date_col_with_timestamp(vectorized::IColumn* col_ptr, const rapidjson::Value& col,
+                                         PrimitiveType type);
 
 private:
     std::string _scroll_id;
diff --git a/be/src/exec/es_http_scan_node.cpp b/be/src/exec/es_http_scan_node.cpp
index 012110d..7b67486 100644
--- a/be/src/exec/es_http_scan_node.cpp
+++ b/be/src/exec/es_http_scan_node.cpp
@@ -437,10 +437,17 @@ void EsHttpScanNode::scanner_worker(int start_idx, int length, std::promise<Stat
             properties, _column_names, _predicates, _docvalue_context, &doc_value_mode);
 
     // start scanner to scan
-    std::unique_ptr<EsHttpScanner> scanner(
-            new EsHttpScanner(_runtime_state, runtime_profile(), _tuple_id, properties,
-                              scanner_expr_ctxs, &counter, doc_value_mode));
-    status = scanner_scan(std::move(scanner), scanner_expr_ctxs, &counter);
+    if (!_vectorized) {
+        std::unique_ptr<EsHttpScanner> scanner(
+                new EsHttpScanner(_runtime_state, runtime_profile(), _tuple_id, properties,
+                                  scanner_expr_ctxs, &counter, doc_value_mode));
+        status = scanner_scan(std::move(scanner), scanner_expr_ctxs, &counter);
+    } else {
+        std::unique_ptr<VEsHttpScanner> scanner(
+                new VEsHttpScanner(_runtime_state, runtime_profile(), _tuple_id, properties,
+                                  scanner_expr_ctxs, &counter, doc_value_mode));
+        status = scanner_scan(std::move(scanner));
+    }
     if (!status.ok()) {
         LOG(WARNING) << "Scanner[" << start_idx
                      << "] process failed. status=" << status.get_error_msg();
diff --git a/be/src/exec/es_http_scan_node.h b/be/src/exec/es_http_scan_node.h
index 640ea0c..b90bf0e 100644
--- a/be/src/exec/es_http_scan_node.h
+++ b/be/src/exec/es_http_scan_node.h
@@ -29,6 +29,7 @@
 
 #include "common/status.h"
 #include "exec/es_http_scanner.h"
+#include "vec/exec/ves_http_scanner.h"
 #include "exec/scan_node.h"
 #include "gen_cpp/PaloInternalService_types.h"
 
@@ -56,7 +57,6 @@ protected:
     // Write debug string of this into out.
     virtual void debug_string(int indentation_level, std::stringstream* out) const override;
 
-private:
     // Update process status to one failed status,
     // NOTE: Must hold the mutex of this scan node
     bool update_status(const Status& new_status) {
@@ -67,20 +67,8 @@ private:
         return false;
     }
 
-    // Create scanners to do scan job
-    Status start_scanners();
-
-    // Collect all scanners 's status
-    Status collect_scanners_status();
-
     // One scanner worker, This scanner will handle 'length' ranges start from start_idx
-    void scanner_worker(int start_idx, int length, std::promise<Status>& p_status);
-
-    // Scan one range
-    Status scanner_scan(std::unique_ptr<EsHttpScanner> scanner,
-                        const std::vector<ExprContext*>& conjunct_ctxs, EsScanCounter* counter);
-
-    Status build_conjuncts_list();
+    virtual void scanner_worker(int start_idx, int length, std::promise<Status>& p_status);
 
     TupleId _tuple_id;
     RuntimeState* _runtime_state;
@@ -92,20 +80,41 @@ private:
     int _max_buffered_batches;
     RuntimeProfile::Counter* _wait_scanner_timer;
 
-    bool _all_scanners_finished;
     Status _process_status;
 
+    std::map<std::string, std::string> _docvalue_context;
+
+    std::condition_variable _queue_reader_cond;
+    std::condition_variable _queue_writer_cond;
+    bool _vectorized = false;
+
+private:
+    // Create scanners to do scan job
+    Status start_scanners();
+
+    // Collect all scanners 's status
+    Status collect_scanners_status();
+
+    // Scan one range
+    Status scanner_scan(std::unique_ptr<EsHttpScanner> scanner,
+                        const std::vector<ExprContext*>& conjunct_ctxs, EsScanCounter* counter);
+
+    virtual Status scanner_scan(std::unique_ptr<VEsHttpScanner> scanner) {
+            return Status::NotSupported("vectorized scan in EsHttpScanNode is not supported!");
+    };
+
+    Status build_conjuncts_list();
+
+    bool _all_scanners_finished;
+
     std::vector<std::thread> _scanner_threads;
     std::vector<std::promise<Status>> _scanners_status;
     std::map<std::string, std::string> _properties;
-    std::map<std::string, std::string> _docvalue_context;
     std::map<std::string, std::string> _fields_context;
     std::vector<TScanRangeParams> _scan_ranges;
     std::vector<std::string> _column_names;
 
     std::mutex _batch_queue_lock;
-    std::condition_variable _queue_reader_cond;
-    std::condition_variable _queue_writer_cond;
     std::deque<std::shared_ptr<RowBatch>> _batch_queue;
     std::vector<EsPredicate*> _predicates;
 
diff --git a/be/src/exec/es_http_scanner.h b/be/src/exec/es_http_scanner.h
index 2bade5a..dcebfe1 100644
--- a/be/src/exec/es_http_scanner.h
+++ b/be/src/exec/es_http_scanner.h
@@ -68,7 +68,7 @@ public:
 
     void close();
 
-private:
+protected:
     RuntimeState* _state;
     RuntimeProfile* _profile;
     TupleId _tuple_id;
diff --git a/be/src/exec/exec_node.cpp b/be/src/exec/exec_node.cpp
index d692a79..97c3259 100644
--- a/be/src/exec/exec_node.cpp
+++ b/be/src/exec/exec_node.cpp
@@ -63,6 +63,26 @@
 #include "util/debug_util.h"
 #include "util/runtime_profile.h"
 
+#include "vec/core/block.h"
+#include "vec/exec/join/vhash_join_node.h"
+#include "vec/exec/vaggregation_node.h"
+#include "vec/exec/ves_http_scan_node.h"
+#include "vec/exec/vcross_join_node.h"
+#include "vec/exec/vexchange_node.h"
+#include "vec/exec/vmysql_scan_node.h"
+#include "vec/exec/vodbc_scan_node.h"
+#include "vec/exec/volap_scan_node.h"
+#include "vec/exec/vsort_node.h"
+#include "vec/exec/vunion_node.h"
+#include "vec/exec/vintersect_node.h"
+#include "vec/exec/vexcept_node.h"
+#include "vec/exec/vanalytic_eval_node.h"
+#include "vec/exec/vassert_num_rows_node.h"
+#include "vec/exec/vselect_node.h"
+#include "vec/exprs/vexpr.h"
+#include "vec/exec/vempty_set_node.h"
+#include "vec/exec/vschema_scan_node.h"
+#include "vec/exec/vrepeat_node.h"
 namespace doris {
 
 const std::string ExecNode::ROW_THROUGHPUT_COUNTER = "RowsReturnedRate";
@@ -167,6 +187,9 @@ Status ExecNode::init(const TPlanNode& tnode, RuntimeState* state) {
     init_runtime_profile(profile);
 
     if (tnode.__isset.vconjunct) {
+        _vconjunct_ctx_ptr.reset(new doris::vectorized::VExprContext*);
+        RETURN_IF_ERROR(doris::vectorized::VExpr::create_expr_tree(_pool, tnode.vconjunct,
+                                                                   _vconjunct_ctx_ptr.get()));
     }
     RETURN_IF_ERROR(Expr::create_expr_trees(_pool, tnode.conjuncts, &_conjunct_ctxs));
 
@@ -189,6 +212,9 @@ Status ExecNode::prepare(RuntimeState* state) {
                                                   _mem_tracker);
     _expr_mem_pool.reset(new MemPool(_expr_mem_tracker.get()));
 
+    if (_vconjunct_ctx_ptr) {
+        RETURN_IF_ERROR((*_vconjunct_ctx_ptr)->prepare(state, row_desc(), expr_mem_tracker()));
+    }
     RETURN_IF_ERROR(Expr::prepare(_conjunct_ctxs, state, row_desc(), expr_mem_tracker()));
 
     // TODO(zc):
@@ -202,6 +228,9 @@ Status ExecNode::prepare(RuntimeState* state) {
 
 Status ExecNode::open(RuntimeState* state) {
     RETURN_IF_ERROR(exec_debug_action(TExecNodePhase::OPEN));
+    if (_vconjunct_ctx_ptr) {
+        RETURN_IF_ERROR((*_vconjunct_ctx_ptr)->open(state));
+    }
     return Expr::open(_conjunct_ctxs, state);
 }
 
@@ -240,6 +269,7 @@ Status ExecNode::close(RuntimeState* state) {
         }
     }
 
+    if (_vconjunct_ctx_ptr) (*_vconjunct_ctx_ptr)->close(state);
     Expr::close(_conjunct_ctxs, state);
 
     if (expr_mem_pool() != nullptr) {
@@ -339,12 +369,42 @@ Status ExecNode::create_tree_helper(RuntimeState* state, ObjectPool* pool,
 
 Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanNode& tnode,
                              const DescriptorTbl& descs, ExecNode** node) {
+    std::stringstream error_msg;
+
     if (state->enable_vectorized_exec()) {
-        return Status::InternalError("unsupport enable_vectorized_engine");
+        switch (tnode.node_type) {
+        case TPlanNodeType::OLAP_SCAN_NODE:
+        case TPlanNodeType::ASSERT_NUM_ROWS_NODE:
+        case TPlanNodeType::HASH_JOIN_NODE:
+        case TPlanNodeType::AGGREGATION_NODE:
+        case TPlanNodeType::UNION_NODE:
+        case TPlanNodeType::CROSS_JOIN_NODE:
+        case TPlanNodeType::SORT_NODE:
+        case TPlanNodeType::EXCHANGE_NODE:
+        case TPlanNodeType::ODBC_SCAN_NODE:
+        case TPlanNodeType::MYSQL_SCAN_NODE:
+        case TPlanNodeType::INTERSECT_NODE:
+        case TPlanNodeType::EXCEPT_NODE:
+        case TPlanNodeType::ES_HTTP_SCAN_NODE:
+        case TPlanNodeType::EMPTY_SET_NODE:
+        case TPlanNodeType::SCHEMA_SCAN_NODE:
+        case TPlanNodeType::ANALYTIC_EVAL_NODE:
+        case TPlanNodeType::SELECT_NODE:
+        case TPlanNodeType::REPEAT_NODE:
+            break;
+        default: {
+            const auto& i = _TPlanNodeType_VALUES_TO_NAMES.find(tnode.node_type);
+            const char* str = "unknown node type";
+
+            if (i != _TPlanNodeType_VALUES_TO_NAMES.end()) {
+                str = i->second;
+            }
+            error_msg << "V" << str << " not implemented";
+            return Status::InternalError(error_msg.str());
+        }
+        }
     }
 
-    std::stringstream error_msg;
-
     VLOG_CRITICAL << "tnode:\n" << apache::thrift::ThriftDebugString(tnode);
     switch (tnode.node_type) {
     case TPlanNodeType::CSV_SCAN_NODE:
@@ -353,14 +413,20 @@ Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanN
 
     case TPlanNodeType::MYSQL_SCAN_NODE:
 #ifdef DORIS_WITH_MYSQL
-        *node = pool->add(new MysqlScanNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VMysqlScanNode(pool, tnode, descs));
+        } else
+            *node = pool->add(new MysqlScanNode(pool, tnode, descs));
         return Status::OK();
 #else
         return Status::InternalError(
                 "Don't support MySQL table, you should rebuild Doris with WITH_MYSQL option ON");
 #endif
     case TPlanNodeType::ODBC_SCAN_NODE:
-        *node = pool->add(new OdbcScanNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VOdbcScanNode(pool, tnode, descs));
+        } else
+            *node = pool->add(new OdbcScanNode(pool, tnode, descs));
         return Status::OK();
 
     case TPlanNodeType::ES_SCAN_NODE:
@@ -368,15 +434,24 @@ Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanN
         return Status::OK();
 
     case TPlanNodeType::ES_HTTP_SCAN_NODE:
-        *node = pool->add(new EsHttpScanNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VEsHttpScanNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new EsHttpScanNode(pool, tnode, descs));
+        }
         return Status::OK();
 
     case TPlanNodeType::SCHEMA_SCAN_NODE:
-        *node = pool->add(new SchemaScanNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VSchemaScanNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new SchemaScanNode(pool, tnode, descs));
+        }
         return Status::OK();
 
     case TPlanNodeType::OLAP_SCAN_NODE:
         if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VOlapScanNode(pool, tnode, descs));
         } else {
             *node = pool->add(new OlapScanNode(pool, tnode, descs));
         }
@@ -384,6 +459,7 @@ Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanN
 
     case TPlanNodeType::AGGREGATION_NODE:
         if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::AggregationNode(pool, tnode, descs));
         } else {
             if (config::enable_partitioned_aggregation) {
                 *node = pool->add(new PartitionedAggregationNode(pool, tnode, descs));
@@ -394,11 +470,16 @@ Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanN
         return Status::OK();
 
     case TPlanNodeType::HASH_JOIN_NODE:
-        *node = pool->add(new HashJoinNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::HashJoinNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new HashJoinNode(pool, tnode, descs));
+        }
         return Status::OK();
 
     case TPlanNodeType::CROSS_JOIN_NODE:
         if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VCrossJoinNode(pool, tnode, descs));
         } else {
             *node = pool->add(new CrossJoinNode(pool, tnode, descs));
         }
@@ -409,18 +490,27 @@ Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanN
         return Status::OK();
 
     case TPlanNodeType::EMPTY_SET_NODE:
-        *node = pool->add(new EmptySetNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VEmptySetNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new EmptySetNode(pool, tnode, descs));
+        }
         return Status::OK();
 
     case TPlanNodeType::EXCHANGE_NODE:
         if (state->enable_vectorized_exec()) {
+            *node = pool->add(new doris::vectorized::VExchangeNode(pool, tnode, descs));
         } else {
             *node = pool->add(new ExchangeNode(pool, tnode, descs));
         }
         return Status::OK();
 
     case TPlanNodeType::SELECT_NODE:
-        *node = pool->add(new SelectNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new doris::vectorized::VSelectNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new SelectNode(pool, tnode, descs));
+        }
         return Status::OK();
 
     case TPlanNodeType::OLAP_REWRITE_NODE:
@@ -429,6 +519,7 @@ Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanN
 
     case TPlanNodeType::SORT_NODE:
         if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VSortNode(pool, tnode, descs));
         } else {
             if (tnode.sort_node.use_top_n) {
                 *node = pool->add(new TopNNode(pool, tnode, descs));
@@ -439,8 +530,12 @@ Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanN
 
         return Status::OK();
     case TPlanNodeType::ANALYTIC_EVAL_NODE:
-        *node = pool->add(new AnalyticEvalNode(pool, tnode, descs));
-        break;
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VAnalyticEvalNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new AnalyticEvalNode(pool, tnode, descs));
+        }
+        return Status::OK();
 
     case TPlanNodeType::MERGE_NODE:
         *node = pool->add(new MergeNode(pool, tnode, descs));
@@ -448,17 +543,26 @@ Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanN
 
     case TPlanNodeType::UNION_NODE:
         if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VUnionNode(pool, tnode, descs));
         } else {
             *node = pool->add(new UnionNode(pool, tnode, descs));
         }
         return Status::OK();
 
     case TPlanNodeType::INTERSECT_NODE:
-        *node = pool->add(new IntersectNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VIntersectNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new IntersectNode(pool, tnode, descs));
+        }
         return Status::OK();
 
     case TPlanNodeType::EXCEPT_NODE:
-        *node = pool->add(new ExceptNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VExceptNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new ExceptNode(pool, tnode, descs));
+        }
         return Status::OK();
 
     case TPlanNodeType::BROKER_SCAN_NODE:
@@ -466,11 +570,19 @@ Status ExecNode::create_node(RuntimeState* state, ObjectPool* pool, const TPlanN
         return Status::OK();
 
     case TPlanNodeType::REPEAT_NODE:
-        *node = pool->add(new RepeatNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VRepeatNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new RepeatNode(pool, tnode, descs));
+        }
         return Status::OK();
 
     case TPlanNodeType::ASSERT_NUM_ROWS_NODE:
-        *node = pool->add(new AssertNumRowsNode(pool, tnode, descs));
+        if (state->enable_vectorized_exec()) {
+            *node = pool->add(new vectorized::VAssertNumRowsNode(pool, tnode, descs));
+        } else {
+            *node = pool->add(new AssertNumRowsNode(pool, tnode, descs));
+        }
         return Status::OK();
 
     case TPlanNodeType::TABLE_FUNCTION_NODE:
@@ -637,6 +749,22 @@ Status ExecNode::claim_buffer_reservation(RuntimeState* state) {
 Status ExecNode::release_unused_reservation() {
     return _buffer_pool_client.DecreaseReservationTo(_resource_profile.min_reservation);
 }
+
+void ExecNode::release_block_memory(vectorized::Block& block, uint16_t child_idx) {
+    DCHECK(child_idx < _children.size());
+    block.clear_column_data(child(child_idx)->row_desc().num_materialized_slots());
+}
+
+void ExecNode::reached_limit(vectorized::Block* block, bool* eos) {
+    if (_limit != -1 and _num_rows_returned + block->rows() >= _limit) {
+        block->set_num_rows(_limit - _num_rows_returned);
+        *eos = true;
+    }
+
+    _num_rows_returned += block->rows();
+    COUNTER_SET(_rows_returned_counter, _num_rows_returned);
+}
+
 /*
 Status ExecNode::enable_deny_reservation_debug_action() {
   DCHECK_EQ(debug_action_, TDebugAction::SET_DENY_RESERVATION_PROBABILITY);
diff --git a/be/src/exec/exec_node.h b/be/src/exec/exec_node.h
index c58f862..7cad500 100644
--- a/be/src/exec/exec_node.h
+++ b/be/src/exec/exec_node.h
@@ -33,6 +33,8 @@
 #include "util/runtime_profile.h"
 #include "util/uid_util.h" // for print_id
 
+#include "vec/exprs/vexpr_context.h"
+
 namespace doris {
 class Expr;
 class ExprContext;
@@ -219,6 +221,15 @@ protected:
     /// fails.
     Status release_unused_reservation();
 
+    /// Release all memory of block which got from child. The block
+    // 1. clear mem of valid column get from child, make sure child can reuse the mem
+    // 2. delete and release the column which create by function all and other reason
+    void release_block_memory(vectorized::Block& block, uint16_t child_idx = 0);
+
+    /// Only use in vectorized exec engine to check whether reach limit and cut num row for block
+    // and add block rows for profile
+    void reached_limit(vectorized::Block* block, bool* eos);
+
     /// Enable the increase reservation denial probability on 'buffer_pool_client_' based on
     /// the 'debug_action_' set on this node. Returns an error if 'debug_action_param_' is
     /// invalid.
@@ -275,6 +286,8 @@ protected:
     std::vector<ExprContext*> _conjunct_ctxs;
     std::vector<TupleId> _tuple_ids;
 
+    std::unique_ptr<doris::vectorized::VExprContext*> _vconjunct_ctx_ptr;
+
     std::vector<ExecNode*> _children;
     RowDescriptor _row_descriptor;
 
diff --git a/be/src/exec/mysql_scan_node.h b/be/src/exec/mysql_scan_node.h
index 6d9d602..ff5fb54 100644
--- a/be/src/exec/mysql_scan_node.h
+++ b/be/src/exec/mysql_scan_node.h
@@ -63,7 +63,7 @@ private:
     // The Mysql value is converted into the appropriate target type.
     Status write_text_slot(char* value, int value_length, SlotDescriptor* slot,
                            RuntimeState* state);
-
+protected:
     bool _is_init;
     MysqlScannerParam _my_param;
     // Name of Mysql table
diff --git a/be/src/exec/odbc_scan_node.cpp b/be/src/exec/odbc_scan_node.cpp
index 6bdc620..ea32cd8 100644
--- a/be/src/exec/odbc_scan_node.cpp
+++ b/be/src/exec/odbc_scan_node.cpp
@@ -29,9 +29,11 @@
 
 namespace doris {
 
-OdbcScanNode::OdbcScanNode(ObjectPool* pool, const TPlanNode& tnode, const DescriptorTbl& descs)
+OdbcScanNode::OdbcScanNode(ObjectPool* pool, const TPlanNode& tnode, const DescriptorTbl& descs,
+                           std::string scan_node_type)
         : ScanNode(pool, tnode, descs),
           _is_init(false),
+          _scan_node_type(scan_node_type),
           _table_name(tnode.odbc_scan_node.table_name),
           _connect_string(std::move(tnode.odbc_scan_node.connect_string)),
           _query_string(std::move(tnode.odbc_scan_node.query_string)),
@@ -42,7 +44,7 @@ OdbcScanNode::OdbcScanNode(ObjectPool* pool, const TPlanNode& tnode, const Descr
 OdbcScanNode::~OdbcScanNode() {}
 
 Status OdbcScanNode::prepare(RuntimeState* state) {
-    VLOG_CRITICAL << "OdbcScanNode::Prepare";
+    VLOG_CRITICAL << _scan_node_type << "::Prepare";
 
     if (_is_init) {
         return Status::OK();
@@ -91,7 +93,7 @@ Status OdbcScanNode::prepare(RuntimeState* state) {
 
 Status OdbcScanNode::open(RuntimeState* state) {
     RETURN_IF_ERROR(ExecNode::open(state));
-    VLOG_CRITICAL << "OdbcScanNode::Open";
+    VLOG_CRITICAL << _scan_node_type << "::Open";
 
     if (nullptr == state) {
         return Status::InternalError("input pointer is null.");
@@ -125,7 +127,7 @@ Status OdbcScanNode::write_text_slot(char* value, int value_length, SlotDescript
 }
 
 Status OdbcScanNode::get_next(RuntimeState* state, RowBatch* row_batch, bool* eos) {
-    VLOG_CRITICAL << "OdbcScanNode::GetNext";
+    VLOG_CRITICAL << _scan_node_type << "::GetNext";
 
     if (nullptr == state || nullptr == row_batch || nullptr == eos) {
         return Status::InternalError("input is nullptr pointer");
@@ -240,7 +242,7 @@ Status OdbcScanNode::close(RuntimeState* state) {
 
 void OdbcScanNode::debug_string(int indentation_level, std::stringstream* out) const {
     *out << string(indentation_level * 2, ' ');
-    *out << "OdbcScanNode(tupleid=" << _tuple_id << " table=" << _table_name;
+    *out << _scan_node_type << "(tupleid=" << _tuple_id << " table=" << _table_name;
     *out << ")" << std::endl;
 
     for (int i = 0; i < _children.size(); ++i) {
diff --git a/be/src/exec/odbc_scan_node.h b/be/src/exec/odbc_scan_node.h
index 393d9ac..1754993 100644
--- a/be/src/exec/odbc_scan_node.h
+++ b/be/src/exec/odbc_scan_node.h
@@ -35,7 +35,8 @@ class Status;
 
 class OdbcScanNode : public ScanNode {
 public:
-    OdbcScanNode(ObjectPool* pool, const TPlanNode& tnode, const DescriptorTbl& descs);
+    OdbcScanNode(ObjectPool* pool, const TPlanNode& tnode, const DescriptorTbl& descs,
+                 std::string scan_node_type = "OdbcScanNode");
     ~OdbcScanNode();
 
     // initialize _odbc_scanner, and create _text_converter.
@@ -53,6 +54,12 @@ public:
 
     // No use
     virtual Status set_scan_ranges(const std::vector<TScanRangeParams>& scan_ranges);
+    const TupleDescriptor* get_tuple_desc() { return _tuple_desc; }
+    TextConverter* get_text_converter() { return _text_converter.get(); }
+    ODBCConnector* get_odbc_scanner() { return _odbc_scanner.get(); }
+    const std::string& get_scan_node_type() { return _scan_node_type; }
+
+    bool is_init() { return _is_init; }
 
 protected:
     // Write debug string of this into out.
@@ -65,6 +72,9 @@ private:
                            RuntimeState* state);
 
     bool _is_init;
+
+    std::string _scan_node_type;
+
     // Name of Odbc table
     std::string _table_name;
 
diff --git a/be/src/exec/olap_scan_node.cpp b/be/src/exec/olap_scan_node.cpp
index ebf8720..dfc9a29 100644
--- a/be/src/exec/olap_scan_node.cpp
+++ b/be/src/exec/olap_scan_node.cpp
@@ -61,7 +61,7 @@ OlapScanNode::OlapScanNode(ObjectPool* pool, const TPlanNode& tnode, const Descr
 
 Status OlapScanNode::init(const TPlanNode& tnode, RuntimeState* state) {
     RETURN_IF_ERROR(ExecNode::init(tnode, state));
-    _direct_conjunct_size = state->enable_vectorized_exec() ? 1 : _conjunct_ctxs.size();
+    _direct_conjunct_size = _conjunct_ctxs.size();
 
     const TQueryOptions& query_options = state->query_options();
     if (query_options.__isset.max_scan_key_num) {
@@ -464,7 +464,6 @@ Status OlapScanNode::start_scan(RuntimeState* state) {
     VLOG_CRITICAL << "Filter idle conjuncts";
     // 5. Filter idle conjunct which already trans to olap filters
     // this must be after build_scan_key, it will free the StringValue memory
-    // TODO: filter idle conjunct in vexpr_contexts
     remove_pushed_conjuncts(state);
 
     VLOG_CRITICAL << "StartScanThread";
@@ -516,6 +515,7 @@ void OlapScanNode::remove_pushed_conjuncts(RuntimeState* state) {
     _conjunct_ctxs = std::move(new_conjunct_ctxs);
     _direct_conjunct_size = new_direct_conjunct_size;
 
+    // TODO: support vbloom_filter_predicate/vbinary_predicate and merge unpushed predicate to _vconjunct_ctx
     for (auto push_down_ctx : _pushed_conjuncts_index) {
         auto iter = _conjunctid_to_runtime_filter_ctxs.find(push_down_ctx);
         if (iter != _conjunctid_to_runtime_filter_ctxs.end()) {
@@ -524,7 +524,13 @@ void OlapScanNode::remove_pushed_conjuncts(RuntimeState* state) {
     }
     // set vconjunct_ctx is empty, if all conjunct
     if (_direct_conjunct_size == 0) {
+        if (_vconjunct_ctx_ptr.get() != nullptr) {
+            (*_vconjunct_ctx_ptr.get())->close(state);
+            _vconjunct_ctx_ptr = nullptr;
+        }
     }
+    // filter idle conjunct in vexpr_contexts
+    _peel_pushed_conjuncts();
 }
 
 void OlapScanNode::eval_const_conjuncts() {
@@ -843,11 +849,6 @@ static bool ignore_cast(SlotDescriptor* slot, Expr* expr) {
 
 bool OlapScanNode::should_push_down_in_predicate(doris::SlotDescriptor* slot,
                                                  doris::InPredicate* pred) {
-    if (pred->is_not_in()) {
-        // can not push down NOT IN predicate to storage engine
-        return false;
-    }
-
     if (Expr::type_without_cast(pred->get_child(0)) != TExprNodeType::SLOT_REF) {
         // not a slot ref(column)
         return false;
@@ -1672,4 +1673,46 @@ Status OlapScanNode::add_one_batch(RowBatch* row_batch) {
 }
 
 
+vectorized::VExpr* OlapScanNode::_dfs_peel_conjunct(vectorized::VExpr* expr, int& leaf_index) {
+    static constexpr auto is_leaf = [](vectorized::VExpr* expr) { return !expr->is_and_expr(); };
+
+    if (is_leaf(expr)) {
+        return _pushed_conjuncts_index.count(leaf_index++) ? nullptr : expr;
+    } else {
+        vectorized::VExpr* left_child = _dfs_peel_conjunct(expr->children()[0], leaf_index);
+        vectorized::VExpr* right_child = _dfs_peel_conjunct(expr->children()[1], leaf_index);
+
+        if (left_child != nullptr && right_child != nullptr) {
+            expr->set_children({left_child, right_child});
+            return expr;
+        }
+        // here do not close Expr* now
+        return left_child != nullptr ? left_child : right_child;
+    }
+}
+
+// This function is used to remove pushed expr in expr tree.
+// It relies on the logic of function convertConjunctsToAndCompoundPredicate() of FE splicing expr.
+// It requires FE to satisfy each splicing with 'and' expr, and spliced from left to right, in order.
+// Expr tree specific forms do not require requirements.
+void OlapScanNode::_peel_pushed_conjuncts() {
+    if (_vconjunct_ctx_ptr.get() == nullptr) return;
+
+    int leaf_index = 0;
+    vectorized::VExpr* conjunct_expr_root = (*_vconjunct_ctx_ptr.get())->root();
+
+    if (conjunct_expr_root != nullptr) {
+        vectorized::VExpr* new_conjunct_expr_root =
+                _dfs_peel_conjunct(conjunct_expr_root, leaf_index);
+        if (new_conjunct_expr_root == nullptr) {
+            _vconjunct_ctx_ptr = nullptr;
+            _scanner_profile->add_info_string("VconjunctExprTree", "null");
+        } else {
+            (*_vconjunct_ctx_ptr.get())->set_root(new_conjunct_expr_root);
+            _scanner_profile->add_info_string("VconjunctExprTree",
+                                              new_conjunct_expr_root->debug_string());
+        }
+    }
+}
+
 } // namespace doris
diff --git a/be/src/exec/olap_scan_node.h b/be/src/exec/olap_scan_node.h
index 3b7df03..f9905e2 100644
--- a/be/src/exec/olap_scan_node.h
+++ b/be/src/exec/olap_scan_node.h
@@ -32,6 +32,8 @@
 #include "runtime/vectorized_row_batch.h"
 #include "util/progress_updater.h"
 #include "util/spinlock.h"
+#include "vec/exec/volap_scanner.h"
+#include "vec/exprs/vexpr.h"
 
 namespace doris {
 class IRuntimeFilter;
@@ -158,6 +160,7 @@ protected:
                             RuntimeProfile* profile);
 
     friend class OlapScanner;
+    friend class doris::vectorized::VOlapScanner;
 
     // Tuple id resolved in prepare() to set _tuple_desc;
     TupleId _tuple_id;
@@ -215,7 +218,7 @@ protected:
 
     std::mutex _scan_batches_lock;
     std::condition_variable _scan_batch_added_cv;
-    int64_t _running_thread = 0;
+    std::atomic_int _running_thread = 0;
     std::condition_variable _scan_thread_exit_cv;
 
     std::list<RowBatch*> _scan_row_batches;
@@ -321,6 +324,9 @@ protected:
     RuntimeProfile::Counter* _scanner_wait_worker_timer = nullptr;
 
     RuntimeProfile::Counter* _olap_wait_batch_queue_timer = nullptr;
+
+    vectorized::VExpr* _dfs_peel_conjunct(vectorized::VExpr* expr, int& leaf_index);
+    void _peel_pushed_conjuncts(); // remove pushed expr from conjunct tree
 };
 
 } // namespace doris
diff --git a/be/src/exec/olap_scanner.cpp b/be/src/exec/olap_scanner.cpp
index af1d658..2e05c5d 100644
--- a/be/src/exec/olap_scanner.cpp
+++ b/be/src/exec/olap_scanner.cpp
@@ -19,9 +19,9 @@
 
 #include <string>
 
-#include "gen_cpp/PaloInternalService_types.h"
 #include "common/utils.h"
 #include "exprs/expr_context.h"
+#include "gen_cpp/PaloInternalService_types.h"
 #include "olap/decimal12.h"
 #include "olap/field.h"
 #include "olap/uint24.h"
@@ -176,8 +176,10 @@ Status OlapScanner::_init_tablet_reader_params(
              _tablet_reader_params.rs_readers[1]->rowset()->start_version() == 2 &&
              !_tablet_reader_params.rs_readers[1]->rowset()->rowset_meta()->is_segments_overlapping());
 
+    _tablet_reader_params.origin_return_columns = &_return_columns;
     if (_aggregation || single_version) {
         _tablet_reader_params.return_columns = _return_columns;
+        _tablet_reader_params.direct_mode = true;
     } else {
         // we need to fetch all key columns to do the right aggregation on storage engine side.
         for (size_t i = 0; i < _tablet->num_key_columns(); ++i) {
@@ -239,7 +241,8 @@ Status OlapScanner::_init_return_columns() {
             }
         }
         if (auto sequence_col_idx = _tablet->tablet_schema().sequence_col_idx();
-            has_replace_col && std::find(_return_columns.begin(), _return_columns.end(), sequence_col_idx) == _return_columns.end()) {
+            has_replace_col && std::find(_return_columns.begin(), _return_columns.end(),
+                                         sequence_col_idx) == _return_columns.end()) {
             _return_columns.push_back(sequence_col_idx);
         }
     }
diff --git a/be/src/exec/olap_scanner.h b/be/src/exec/olap_scanner.h
index f234925..0c684d9 100644
--- a/be/src/exec/olap_scanner.h
+++ b/be/src/exec/olap_scanner.h
@@ -58,7 +58,7 @@ public:
 
     Status open();
 
-    Status get_batch(RuntimeState* state, RowBatch* batch, bool* eof);
+    virtual Status get_batch(RuntimeState* state, RowBatch* batch, bool* eof);
 
     Status close(RuntimeState* state);
 
@@ -103,7 +103,7 @@ protected:
     // Update profile that need to be reported in realtime.
     void _update_realtime_counter();
 
-    virtual void set_tablet_reader() { _tablet_reader.reset(new TupleReader); }
+    virtual void set_tablet_reader() { _tablet_reader = std::make_unique<TupleReader>(); }
 
 protected:
     RuntimeState* _runtime_state;
diff --git a/be/src/exec/partitioned_aggregation_node.cc b/be/src/exec/partitioned_aggregation_node.cc
index 2311f82..68f536f 100644
--- a/be/src/exec/partitioned_aggregation_node.cc
+++ b/be/src/exec/partitioned_aggregation_node.cc
@@ -1048,7 +1048,7 @@ Tuple* PartitionedAggregationNode::GetOutputTuple(const vector<NewAggFnEvaluator
     }
     if (needs_finalize_) {
         NewAggFnEvaluator::Finalize(agg_fn_evals, tuple, dst,
-                                    grouping_exprs_.size() == 0 && child(0)->rows_returned() == 0);
+                grouping_exprs_.size() == 0 && child(0)->rows_returned() == 0);
     } else {
         NewAggFnEvaluator::Serialize(agg_fn_evals, tuple);
     }
diff --git a/be/src/exec/repeat_node.h b/be/src/exec/repeat_node.h
index 01335d2..d9dce75 100644
--- a/be/src/exec/repeat_node.h
+++ b/be/src/exec/repeat_node.h
@@ -40,7 +40,7 @@ public:
 protected:
     virtual void debug_string(int indentation_level, std::stringstream* out) const override;
 
-private:
+protected:
     Status get_repeated_batch(RowBatch* child_row_batch, int repeat_id_idx, RowBatch* row_batch);
 
     // Slot id set used to indicate those slots need to set to null.
diff --git a/be/src/exec/scan_node.h b/be/src/exec/scan_node.h
index 5f8ec4b..bd09991 100644
--- a/be/src/exec/scan_node.h
+++ b/be/src/exec/scan_node.h
@@ -91,7 +91,7 @@ public:
 
 protected:
     RuntimeProfile::Counter* _bytes_read_counter; // # bytes read from the scanner
-    // # rows/tuples read from the scanner (including those discarded by eval_conjucts())
+    // # rows/tuples read from the scanner (including those discarded by eval_conjuncts())
     RuntimeProfile::Counter* _rows_read_counter;
     // Wall based aggregate read throughput [bytes/sec]
     RuntimeProfile::Counter* _total_throughput_counter;
diff --git a/be/src/exec/schema_scan_node.h b/be/src/exec/schema_scan_node.h
index 2052de0..f45086c 100644
--- a/be/src/exec/schema_scan_node.h
+++ b/be/src/exec/schema_scan_node.h
@@ -62,7 +62,7 @@ private:
     void debug_string(int indentation_level, std::stringstream* out) const override;
     // Copy one row from schema table to input tuple
     void copy_one_row();
-
+protected:
     bool _is_init;
     const std::string _table_name;
     SchemaScannerParam _scanner_param;
diff --git a/be/src/exec/tablet_info.cpp b/be/src/exec/tablet_info.cpp
index 7d470bf..a1195d5 100644
--- a/be/src/exec/tablet_info.cpp
+++ b/be/src/exec/tablet_info.cpp
@@ -407,4 +407,228 @@ uint32_t OlapTablePartitionParam::_compute_dist_hash(Tuple* key) const {
     return hash_val;
 }
 
+VOlapTablePartitionParam::VOlapTablePartitionParam(std::shared_ptr<OlapTableSchemaParam>& schema,
+                                                 const TOlapTablePartitionParam& t_param)
+        : _schema(schema),
+          _t_param(t_param),
+          _slots(_schema->tuple_desc()->slots()),
+          _mem_tracker(MemTracker::CreateTracker(-1, "OlapTablePartitionParam")) {
+    for (auto slot : _slots) {
+        _partition_block.insert({slot->get_empty_mutable_column(), slot->get_data_type_ptr(), slot->col_name()});
+    }
+}
+
+VOlapTablePartitionParam::~VOlapTablePartitionParam() {
+    _mem_tracker->Release(_mem_usage);
+}
+
+Status VOlapTablePartitionParam::init() {
+    std::vector<std::string> slot_column_names;
+    for (auto slot_desc : _schema->tuple_desc()->slots()) {
+        slot_column_names.emplace_back(slot_desc->col_name());
+    }
+
+    auto find_slot_locs = [&slot_column_names](const std::string& slot_name, std::vector<uint16_t>& locs, const std::string& column_type) {
+        auto it = std::find(slot_column_names.begin(), slot_column_names.end(), slot_name);
+        if (it == slot_column_names.end()) {
+            return Status::InternalError(column_type + " column not found, column =" + slot_name);
+        }
+        locs.emplace_back(it - slot_column_names.begin());
+        return Status::OK();
+    };
+
+    if (_t_param.__isset.partition_columns) {
+        for (auto& part_col : _t_param.partition_columns) {
+            RETURN_IF_ERROR(find_slot_locs(part_col, _partition_slot_locs, "partition"));
+        }
+    }
+
+    _partitions_map.reset(new std::map<BlockRow*, VOlapTablePartition*, VOlapTablePartKeyComparator>(
+            VOlapTablePartKeyComparator(_partition_slot_locs)));
+    if (_t_param.__isset.distributed_columns) {
+        for (auto& col : _t_param.distributed_columns) {
+            RETURN_IF_ERROR(find_slot_locs(col, _distributed_slot_locs, "distributed"));
+        }
+    }
+
+    DCHECK(!_t_param.partitions.empty()) << "must have at least 1 partition";
+    _is_in_partition = _t_param.partitions[0].__isset.in_keys;
+
+    // initial partitions
+    for (int i = 0; i < _t_param.partitions.size(); ++i) {
+        const TOlapTablePartition& t_part = _t_param.partitions[i];
+        auto part = _obj_pool.add(new VOlapTablePartition(&_partition_block));
+        part->id = t_part.id;
+
+        if (!_is_in_partition) {
+            if (t_part.__isset.start_keys) {
+                RETURN_IF_ERROR(_create_partition_keys(t_part.start_keys, &part->start_key));
+            }
+
+            if (t_part.__isset.end_keys) {
+                RETURN_IF_ERROR(_create_partition_keys(t_part.end_keys, &part->end_key));
+            }
+        } else {
+            for (const auto& keys : t_part.in_keys) {
+                RETURN_IF_ERROR(_create_partition_keys(keys, &part->in_keys.emplace_back(&_partition_block, -1)));
+            }
+        }
+
+        part->num_buckets = t_part.num_buckets;
+        auto num_indexes = _schema->indexes().size();
+        if (t_part.indexes.size() != num_indexes) {
+            std::stringstream ss;
+            ss << "number of partition's index is not equal with schema's"
+               << ", num_part_indexes=" << t_part.indexes.size()
+               << ", num_schema_indexes=" << num_indexes;
+            return Status::InternalError(ss.str());
+        }
+        part->indexes = t_part.indexes;
+        std::sort(part->indexes.begin(), part->indexes.end(),
+                  [](const OlapTableIndexTablets& lhs, const OlapTableIndexTablets& rhs) {
+                      return lhs.index_id < rhs.index_id;
+                  });
+        // check index
+        for (int j = 0; j < num_indexes; ++j) {
+            if (part->indexes[j].index_id != _schema->indexes()[j]->index_id) {
+                std::stringstream ss;
+                ss << "partition's index is not equal with schema's"
+                   << ", part_index=" << part->indexes[j].index_id
+                   << ", schema_index=" << _schema->indexes()[j]->index_id;
+                return Status::InternalError(ss.str());
+            }
+        }
+        _partitions.emplace_back(part);
+        if (_is_in_partition) {
+            for (auto& in_key : part->in_keys) {
+                _partitions_map->emplace(&in_key, part);
+            }
+        } else {
+            _partitions_map->emplace(&part->end_key, part);
+        }
+    }
+
+    _mem_usage = _partition_block.allocated_bytes();
+    _mem_tracker->Consume(_mem_usage);
+    return Status::OK();
+}
+
+bool VOlapTablePartitionParam::find_tablet(BlockRow* block_row, const VOlapTablePartition** partition,
+                                           uint32_t* dist_hashes) const {
+    auto it = _is_in_partition ? _partitions_map->find(block_row) : _partitions_map->upper_bound(block_row);
+    if (it == _partitions_map->end()) {
+        return false;
+    }
+    if (_is_in_partition || _part_contains(it->second, block_row)) {
+        *partition = it->second;
+        *dist_hashes = _compute_dist_hash(block_row);
+        return true;
+    }
+    return false;
+}
+
+Status VOlapTablePartitionParam::_create_partition_keys(const std::vector<TExprNode>& t_exprs,
+                                                       BlockRow* part_key) {
+    for (int i = 0; i < t_exprs.size(); i++) {
+        RETURN_IF_ERROR(_create_partition_key(t_exprs[i], part_key->first,
+                _partition_slot_locs[i]));
+    }
+    return Status::OK();
+}
+
+Status VOlapTablePartitionParam::_create_partition_key(const TExprNode& t_expr, vectorized::Block* block,
+                                                      uint16_t pos) {
+    auto column = std::move(*block->get_by_position(pos).column).mutate();
+    switch (t_expr.node_type) {
+    case TExprNodeType::DATE_LITERAL: {
+        vectorized::VecDateTimeValue dt;
+        if (!dt.from_date_str(
+                    t_expr.date_literal.value.c_str(), t_expr.date_literal.value.size())) {
+            std::stringstream ss;
+            ss << "invalid date literal in partition column, date=" << t_expr.date_literal;
+            return Status::InternalError(ss.str());
+        }
+        column->insert_data(reinterpret_cast<const char *>(&dt), 0);
+        break;
+    }
+    case TExprNodeType::INT_LITERAL: {
+        switch (t_expr.type.types[0].scalar_type.type) {
+            case TPrimitiveType::TINYINT: {
+                int8_t value = t_expr.int_literal.value;
+                column->insert_data(reinterpret_cast<const char *>(&value), 0);
+                break;
+            }
+            case TPrimitiveType::SMALLINT: {
+                int16_t value = t_expr.int_literal.value;
+                column->insert_data(reinterpret_cast<const char *>(&value), 0);
+                break;
+            }
+            case TPrimitiveType::INT: {
+                int32_t value = t_expr.int_literal.value;
+                column->insert_data(reinterpret_cast<const char *>(&value), 0);
+                break;
+            }
+            default:
+                int64_t value = t_expr.int_literal.value;
+                column->insert_data(reinterpret_cast<const char *>(&value), 0);
+        }
+        break;
+    } case TExprNodeType::LARGE_INT_LITERAL: {
+        StringParser::ParseResult parse_result = StringParser::PARSE_SUCCESS;
+        __int128 value = StringParser::string_to_int<__int128>(t_expr.large_int_literal.value.c_str(),
+                                                             t_expr.large_int_literal.value.size(),
+                                                             &parse_result);
+        if (parse_result != StringParser::PARSE_SUCCESS) {
+            value = MAX_INT128;
+        }
+        column->insert_data(reinterpret_cast<const char *>(&value), 0);
+        break;
+    } case TExprNodeType::STRING_LITERAL: {
+        int len = t_expr.string_literal.value.size();
+        const char* str_val = t_expr.string_literal.value.c_str();
+
+        // CHAR is a fixed-length string and needs to use the length in the slot definition,
+        // VARVHAR is a variable-length string and needs to use the length of the string itself
+        // padding 0 to CHAR field
+//        if (TYPE_CHAR == slot_desc->type().type && len < slot_desc->type().len) {
+//            auto new_ptr = (char*)_mem_pool->allocate(slot_desc->type().len);
+//            memset(new_ptr, 0, slot_desc->type().len);
+//            memcpy(new_ptr, str_val, len);
+//
+//            str_val = new_ptr;
+//            len = slot_desc->type().len;
+//        }
+        column->insert_data(str_val, len);
+        break;
+    } case TExprNodeType::BOOL_LITERAL: {
+        column->insert_data(reinterpret_cast<const char *>(&t_expr.bool_literal.value), 0);
+        break;
+    } default: {
+        std::stringstream ss;
+        ss << "unsupported partition column node type, type=" << t_expr.node_type;
+        return Status::InternalError(ss.str());
+    }
+    }
+    return Status::OK();
+}
+
+uint32_t VOlapTablePartitionParam::_compute_dist_hash(BlockRow* key) const {
+    uint32_t hash_val = 0;
+    for (int i = 0; i < _distributed_slot_locs.size(); ++i) {
+        auto slot_desc = _slots[_distributed_slot_locs[i]];
+        auto column = key->first->get_by_position(_distributed_slot_locs[i]).column;
+
+        auto val = column->get_data_at(key->second);
+        if (val.data != nullptr) {
+            hash_val = RawValue::zlib_crc32(val.data, val.size, slot_desc->type().type, hash_val);
+        } else {
+            // NULL is treat as 0 when hash
+            static const int INT_VALUE = 0;
+            static const TypeDescriptor INT_TYPE(TYPE_INT);
+            hash_val = RawValue::zlib_crc32(&INT_VALUE, INT_TYPE, hash_val);
+        }
+    }
+    return hash_val;
+}
+
 } // namespace doris
diff --git a/be/src/exec/tablet_info.h b/be/src/exec/tablet_info.h
index 7bb2640..53221ba 100644
--- a/be/src/exec/tablet_info.h
+++ b/be/src/exec/tablet_info.h
@@ -31,6 +31,8 @@
 #include "runtime/raw_value.h"
 #include "runtime/tuple.h"
 
+#include "vec/core/block.h"
+
 namespace doris {
 
 class MemPool;
@@ -205,6 +207,104 @@ private:
             _partitions_map;
 };
 
+using BlockRow = std::pair<vectorized::Block*, int32_t>;
+
+struct VOlapTablePartition {
+    int64_t id = 0;
+    BlockRow start_key;
+    BlockRow end_key;
+    std::vector<BlockRow> in_keys;
+    int64_t num_buckets = 0;
+    std::vector<OlapTableIndexTablets> indexes;
+
+    VOlapTablePartition(vectorized::Block* partition_block):
+        start_key{partition_block, -1}, end_key{partition_block, -1} {};
+};
+
+class VOlapTablePartKeyComparator {
+public:
+    VOlapTablePartKeyComparator(const std::vector<uint16_t>& slot_locs)
+            : _slot_locs(slot_locs) {}
+
+    // return true if lhs < rhs
+    // 'row' is -1 mean
+    bool operator()(const BlockRow* lhs, const BlockRow* rhs) const {
+        if (lhs->second == -1) {
+            return false;
+        } else if (rhs->second == -1) {
+            return true;
+        }
+
+        for (auto slot_loc : _slot_locs) {
+            auto res = lhs->first->get_by_position(slot_loc).column->compare_at(
+                    lhs->second, rhs->second, *rhs->first->get_by_position(slot_loc).column, -1);
+            if (res != 0) {
+                return res < 0;
+            }
+        }
+        // equal, return false
+        return false;
+    }
+
+private:
+    const std::vector<uint16_t>& _slot_locs;
+};
+
+// store an olap table's tablet information
+class VOlapTablePartitionParam {
+public:
+    VOlapTablePartitionParam(std::shared_ptr<OlapTableSchemaParam>& schema,
+                            const TOlapTablePartitionParam& param);
+
+    ~VOlapTablePartitionParam();
+
+    Status init();
+
+    int64_t db_id() const { return _t_param.db_id; }
+    int64_t table_id() const { return _t_param.table_id; }
+    int64_t version() const { return _t_param.version; }
+
+    // return true if we found this tuple in partition
+    bool find_tablet(BlockRow* block_row, const VOlapTablePartition** partitions,
+                     uint32_t* dist_hash) const;
+
+    const std::vector<VOlapTablePartition*>& get_partitions() const { return _partitions; }
+
+private:
+    Status _create_partition_keys(const std::vector<TExprNode>& t_exprs, BlockRow* part_key);
+
+    Status _create_partition_key(const TExprNode& t_expr, vectorized::Block* block, uint16_t pos);
+
+    uint32_t _compute_dist_hash(BlockRow* key) const;
+
+    // check if this partition contain this key
+    bool _part_contains(VOlapTablePartition* part, BlockRow* key) const {
+        // start_key.second == -1 means only single partition
+        VOlapTablePartKeyComparator comparator(_partition_slot_locs);
+        return part->start_key.second == -1 || !comparator(key, &part->start_key);
+    }
+
+private:
+    // this partition only valid in this schema
+    std::shared_ptr<OlapTableSchemaParam> _schema;
+    TOlapTablePartitionParam _t_param;
+
+    const std::vector<SlotDescriptor*>& _slots;
+    std::vector<uint16_t> _partition_slot_locs;
+    std::vector<uint16_t> _distributed_slot_locs;
+
+    ObjectPool _obj_pool;
+    vectorized::Block _partition_block;
+    std::shared_ptr<MemTracker> _mem_tracker;
+    std::vector<VOlapTablePartition*> _partitions;
+    std::unique_ptr<std::map<BlockRow*, VOlapTablePartition*, VOlapTablePartKeyComparator>>
+            _partitions_map;
+
+    bool _is_in_partition = false;
+    uint32_t _mem_usage = 0;
+};
+
+
 using TabletLocation = TTabletLocation;
 // struct TTabletLocation {
 //     1: required i64 tablet_id
diff --git a/be/src/exec/tablet_sink.cpp b/be/src/exec/tablet_sink.cpp
index 1718f7d..7acde28 100644
--- a/be/src/exec/tablet_sink.cpp
+++ b/be/src/exec/tablet_sink.cpp
@@ -251,6 +251,53 @@ Status NodeChannel::add_row(Tuple* input_tuple, int64_t tablet_id) {
     return Status::OK();
 }
 
+Status NodeChannel::add_row(BlockRow& block_row, int64_t tablet_id) {
+    // If add_row() when _eos_is_produced==true, there must be sth wrong, we can only mark this channel as failed.
+    auto st = none_of({_cancelled, _eos_is_produced});
+    if (!st.ok()) {
+        if (_cancelled) {
+            std::lock_guard<SpinLock> l(_cancel_msg_lock);
+            return Status::InternalError("add row failed. " + _cancel_msg);
+        } else {
+            return st.clone_and_prepend("already stopped, can't add row. cancelled/eos: ");
+        }
+    }
+
+    // We use OlapTableSink mem_tracker which has the same ancestor of _plan node,
+    // so in the ideal case, mem limit is a matter for _plan node.
+    // But there is still some unfinished things, we do mem limit here temporarily.
+    // _cancelled may be set by rpc callback, and it's possible that _cancelled might be set in any of the steps below.
+    // It's fine to do a fake add_row() and return OK, because we will check _cancelled in next add_row() or mark_close().
+    while (!_cancelled && _parent->_mem_tracker->AnyLimitExceeded(MemLimit::HARD) &&
+           _pending_batches_num > 0) {
+        SCOPED_ATOMIC_TIMER(&_mem_exceeded_block_ns);
+        SleepFor(MonoDelta::FromMilliseconds(10));
+    }
+
+    auto row_no = _cur_batch->add_row();
+    if (row_no == RowBatch::INVALID_ROW_INDEX) {
+        {
+            SCOPED_ATOMIC_TIMER(&_queue_push_lock_ns);
+            std::lock_guard<std::mutex> l(_pending_batches_lock);
+            //To simplify the add_row logic, postpone adding batch into req until the time of sending req
+            _pending_batches.emplace(std::move(_cur_batch), _cur_add_batch_request);
+            _pending_batches_num++;
+        }
+
+        _cur_batch.reset(new RowBatch(*_row_desc, _batch_size, _parent->_mem_tracker.get()));
+        _cur_add_batch_request.clear_tablet_ids();
+
+        row_no = _cur_batch->add_row();
+    }
+    DCHECK_NE(row_no, RowBatch::INVALID_ROW_INDEX);
+
+    _cur_batch->get_row(row_no)->set_tuple(0,
+            block_row.first->deep_copy_tuple(*_tuple_desc, _cur_batch->tuple_data_pool(), block_row.second, 0, true));
+    _cur_batch->commit_last_row();
+    _cur_add_batch_request.add_tablet_ids(tablet_id);
+    return Status::OK();
+}
+
 Status NodeChannel::mark_close() {
     auto st = none_of({_cancelled, _eos_is_produced});
     if (!st.ok()) {
@@ -501,6 +548,29 @@ Status IndexChannel::add_row(Tuple* tuple, int64_t tablet_id) {
     return Status::OK();
 }
 
+Status IndexChannel::add_row(BlockRow& block_row, int64_t tablet_id) {
+    auto it = _channels_by_tablet.find(tablet_id);
+    DCHECK(it != _channels_by_tablet.end()) << "unknown tablet, tablet_id=" << tablet_id;
+    std::stringstream ss;
+    for (auto channel : it->second) {
+        // if this node channel is already failed, this add_row will be skipped
+        auto st = channel->add_row(block_row, tablet_id);
+        if (!st.ok()) {
+            mark_as_failed(channel);
+            ss << st.get_error_msg() << "; ";
+        }
+    }
+
+    if (has_intolerable_failure()) {
+        std::stringstream ss2;
+        ss2 << "index channel has intolerable failure. " << BackendOptions::get_localhost()
+            << ", err: " << ss.str();
+        return Status::InternalError(ss2.str());
+    }
+
+    return Status::OK();
+}
+
 bool IndexChannel::has_intolerable_failure() {
     for (const auto& it : _failed_channels) {
         if (it.second.size() >= ((_parent->_num_replicas + 1) / 2)) {
@@ -731,7 +801,7 @@ Status OlapTableSink::send(RuntimeState* state, RowBatch* input_batch) {
         batch = _output_batch.get();
     }
     int num_invalid_rows = 0;
-    if (_need_validate_data) {
+    {
         SCOPED_RAW_TIMER(&_validate_data_ns);
         _filter_bitmap.Reset(batch->num_rows());
         num_invalid_rows = _validate_data(state, batch, &_filter_bitmap);
diff --git a/be/src/exec/tablet_sink.h b/be/src/exec/tablet_sink.h
index b5e86f7..6f403b1 100644
--- a/be/src/exec/tablet_sink.h
+++ b/be/src/exec/tablet_sink.h
@@ -160,6 +160,8 @@ public:
 
     Status add_row(Tuple* tuple, int64_t tablet_id);
 
+    Status add_row(BlockRow& block_row, int64_t tablet_id);
+
     // two ways to stop channel:
     // 1. mark_close()->close_wait() PS. close_wait() will block waiting for the last AddBatch rpc response.
     // 2. just cancel()
@@ -276,6 +278,8 @@ public:
 
     Status add_row(Tuple* tuple, int64_t tablet_id);
 
+    Status add_row(BlockRow& block_row, int64_t tablet_id);
+
     void for_each_node_channel(const std::function<void(NodeChannel*)>& func) {
         for (auto& it : _node_channels) {
             func(it.second);
@@ -350,7 +354,7 @@ private:
     // only focus on pending batches and channel status, the internal errors of NodeChannels will be handled by the producer
     void _send_batch_process();
 
-private:
+protected:
     friend class NodeChannel;
     friend class IndexChannel;
 
diff --git a/be/src/exec/text_converter.cpp b/be/src/exec/text_converter.cpp
index 7801f66..e2d37d5 100644
--- a/be/src/exec/text_converter.cpp
+++ b/be/src/exec/text_converter.cpp
@@ -59,4 +59,26 @@ void TextConverter::unescape_string(const char* src, char* dest, size_t* len) {
     *len = dest_ptr - dest_start;
 }
 
+void TextConverter::unescape_string_on_spot(const char* src, size_t* len) {
+    char* dest_ptr = const_cast<char*>(src);
+    const char* end = src + *len;
+    bool escape_next_char = false;
+
+    while (src < end) {
+        if (*src == _escape_char) {
+            escape_next_char = !escape_next_char;
+        } else {
+            escape_next_char = false;
+        }
+
+        if (escape_next_char) {
+            ++src;
+        } else {
+            *dest_ptr++ = *src++;
+        }
+    }
+
+    *len = dest_ptr - src;
+}
+
 } // namespace doris
diff --git a/be/src/exec/text_converter.h b/be/src/exec/text_converter.h
index 4d97b7c..36b3254 100644
--- a/be/src/exec/text_converter.h
+++ b/be/src/exec/text_converter.h
@@ -19,7 +19,7 @@
 #define DORIS_BE_SRC_QUERY_EXEC_TEXT_CONVERTER_H
 
 #include "runtime/runtime_state.h"
-
+#include "vec/core/block.h"
 namespace doris {
 
 class MemPool;
@@ -48,11 +48,14 @@ public:
     bool write_slot(const SlotDescriptor* slot_desc, Tuple* tuple, const char* data, int len,
                     bool copy_string, bool need_escape, MemPool* pool);
 
+    bool write_column(const SlotDescriptor* slot_desc, vectorized::MutableColumnPtr* column_ptr,
+                      const char* data, size_t len, bool copy_string, bool need_escape);
+
     // Removes escape characters from len characters of the null-terminated string src,
     // and copies the unescaped string into dest, changing *len to the unescaped length.
     // No null-terminator is added to dest.
     void unescape_string(const char* src, char* dest, size_t* len);
-
+    void unescape_string_on_spot(const char* src, size_t* len);
     // Removes escape characters from 'str', allocating a new string from pool.
     // 'str' is updated with the new ptr and length.
     void unescape_string(StringValue* str, MemPool* pool);
diff --git a/be/src/exec/text_converter.hpp b/be/src/exec/text_converter.hpp
index 1b1a60e..44e807c 100644
--- a/be/src/exec/text_converter.hpp
+++ b/be/src/exec/text_converter.hpp
@@ -17,6 +17,7 @@
 
 #ifndef DORIS_BE_SRC_QUERY_EXEC_TEXT_CONVERTER_HPP
 #define DORIS_BE_SRC_QUERY_EXEC_TEXT_CONVERTER_HPP
+#include <sql.h>
 
 #include <boost/algorithm/string.hpp>
 
@@ -32,7 +33,7 @@
 #include "util/binary_cast.hpp"
 #include "util/string_parser.hpp"
 #include "util/types.h"
-
+#include "vec/runtime/vdatetime_value.h"
 namespace doris {
 
 // Note: this function has a codegen'd version.  Changing this function requires
@@ -165,6 +166,134 @@ inline bool TextConverter::write_slot(const SlotDescriptor* slot_desc, Tuple* tu
     return true;
 }
 
+inline bool TextConverter::write_column(const SlotDescriptor* slot_desc,
+                                        vectorized::MutableColumnPtr* column_ptr, const char* data,
+                                        size_t len, bool copy_string, bool need_escape) {
+    vectorized::IColumn* col_ptr = column_ptr->get();
+    // \N means it's NULL
+    if (true == slot_desc->is_nullable()) {
+        auto* nullable_column = reinterpret_cast<vectorized::ColumnNullable*>(column_ptr->get());
+        if ((len == 2 && data[0] == '\\' && data[1] == 'N') || len == SQL_NULL_DATA) {
+            nullable_column->insert_data(nullptr, 0);
+            return true;
+        } else {
+            nullable_column->get_null_map_data().push_back(0);
+            col_ptr = &nullable_column->get_nested_column();
+        }
+    }
+    StringParser::ParseResult parse_result = StringParser::PARSE_SUCCESS;
+
+    // Parse the raw-text data. Translate the text string to internal format.
+    switch (slot_desc->type().type) {
+    case TYPE_HLL:
+    case TYPE_VARCHAR:
+    case TYPE_CHAR: {
+        if (need_escape) {
+            unescape_string_on_spot(data, &len);
+        }
+        reinterpret_cast<vectorized::ColumnString*>(col_ptr)->insert_data(data, len);
+        break;
+    }
+
+    case TYPE_BOOLEAN: {
+        bool num = StringParser::string_to_bool(data, len, &parse_result);
+        reinterpret_cast<vectorized::ColumnVector<vectorized::UInt8>*>(col_ptr)->insert_value(
+                (uint8_t)num);
+        break;
+    }
+    case TYPE_TINYINT: {
+        int8_t num = StringParser::string_to_int<int8_t>(data, len, &parse_result);
+        reinterpret_cast<vectorized::ColumnVector<vectorized::Int8>*>(col_ptr)->insert_value(num);
+        break;
+    }
+    case TYPE_SMALLINT: {
+        int16_t num = StringParser::string_to_int<int16_t>(data, len, &parse_result);
+        reinterpret_cast<vectorized::ColumnVector<vectorized::Int16>*>(col_ptr)->insert_value(num);
+        break;
+    }
+    case TYPE_INT: {
+        int32_t num = StringParser::string_to_int<int32_t>(data, len, &parse_result);
+        reinterpret_cast<vectorized::ColumnVector<vectorized::Int32>*>(col_ptr)->insert_value(num);
+        break;
+    }
+    case TYPE_BIGINT: {
+        int64_t num = StringParser::string_to_int<int64_t>(data, len, &parse_result);
+        reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_value(num);
+        break;
+    }
+    case TYPE_LARGEINT: {
+        __int128 num = StringParser::string_to_int<__int128>(data, len, &parse_result);
+        reinterpret_cast<vectorized::ColumnVector<vectorized::Int128>*>(col_ptr)->insert_value(num);
+        break;
+    }
+
+    case TYPE_FLOAT: {
+        float num = StringParser::string_to_float<float>(data, len, &parse_result);
+        reinterpret_cast<vectorized::ColumnVector<vectorized::Float32>*>(col_ptr)->insert_value(
+                num);
+        break;
+    }
+    case TYPE_DOUBLE: {
+        double num = StringParser::string_to_float<double>(data, len, &parse_result);
+        reinterpret_cast<vectorized::ColumnVector<vectorized::Float64>*>(col_ptr)->insert_value(
+                num);
+        break;
+    }
+    case TYPE_DATE: {
+        vectorized::VecDateTimeValue ts_slot;
+        if (!ts_slot.from_date_str(data, len)) {
+            parse_result = StringParser::PARSE_FAILURE;
+            break;
+        }
+        ts_slot.cast_to_date();
+        reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_data(
+                reinterpret_cast<char*>(&ts_slot), 0);
+        break;
+    }
+
+    case TYPE_DATETIME: {
+        vectorized::VecDateTimeValue ts_slot;
+        if (!ts_slot.from_date_str(data, len)) {
+            parse_result = StringParser::PARSE_FAILURE;
+            break;
+        }
+        ts_slot.to_datetime();
+        reinterpret_cast<vectorized::ColumnVector<vectorized::Int64>*>(col_ptr)->insert_data(
+                reinterpret_cast<char*>(&ts_slot), 0);
+        break;
+    }
+
+    case TYPE_DECIMALV2: {
+        DecimalV2Value decimal_slot;
+        if (decimal_slot.parse_from_str(data, len)) {
+            parse_result = StringParser::PARSE_FAILURE;
+            break;
+        }
+        PackedInt128 num = binary_cast<DecimalV2Value, PackedInt128>(decimal_slot);
+        reinterpret_cast<vectorized::ColumnVector<doris::PackedInt128>*>(col_ptr)->insert_value(
+                num.value);
+        break;
+    }
+
+    default:
+        DCHECK(false) << "bad slot type: " << slot_desc->type();
+        break;
+    }
+
+    if (parse_result == StringParser::PARSE_FAILURE) {
+        if (true == slot_desc->is_nullable()) {
+            auto* nullable_column =
+                    reinterpret_cast<vectorized::ColumnNullable*>(column_ptr->get());
+            size_t size = nullable_column->get_null_map_data().size();
+            doris::vectorized::NullMap& null_map_data = nullable_column->get_null_map_data();
+            null_map_data[size - 1] = 1;
+        } else {
+            return false;
+        }
+    }
+    return true;
+}
+
 } // namespace doris
 
-#endif
+#endif
\ No newline at end of file
diff --git a/be/src/exprs/CMakeLists.txt b/be/src/exprs/CMakeLists.txt
index 5ebf1d1..5d69aa7 100644
--- a/be/src/exprs/CMakeLists.txt
+++ b/be/src/exprs/CMakeLists.txt
@@ -71,7 +71,6 @@ add_library(Exprs
   hll_function.cpp
   grouping_sets_functions.cpp
   topn_function.cpp
-
   table_function/explode_split.cpp
   table_function/explode_bitmap.cpp
   table_function/explode_json_array.cpp
diff --git a/be/src/exprs/aggregate_functions.cpp b/be/src/exprs/aggregate_functions.cpp
index 1f8db84..93166cf 100644
--- a/be/src/exprs/aggregate_functions.cpp
+++ b/be/src/exprs/aggregate_functions.cpp
@@ -592,30 +592,14 @@ void AggregateFunctions::sum(FunctionContext* ctx, const DecimalV2Val& src, Deci
     }
 
     if (dst->is_null) {
-        dst->is_null = false;
-        dst->set_to_zero();
+        init_zero_not_null<DecimalV2Val>(ctx, dst);
     }
-
     DecimalV2Value new_src = DecimalV2Value::from_decimal_val(src);
     DecimalV2Value new_dst = DecimalV2Value::from_decimal_val(*dst);
     new_dst = new_dst + new_src;
     new_dst.to_decimal_val(dst);
 }
 
-template <>
-void AggregateFunctions::sum(FunctionContext* ctx, const LargeIntVal& src, LargeIntVal* dst) {
-    if (src.is_null) {
-        return;
-    }
-
-    if (dst->is_null) {
-        dst->is_null = false;
-        dst->val = 0;
-    }
-
-    dst->val += src.val;
-}
-
 template <typename T>
 void AggregateFunctions::min_init(FunctionContext* ctx, T* dst) {
     auto val = AnyValUtil::max_val<T>(ctx);
@@ -1890,8 +1874,8 @@ static double compute_knuth_variance(const KnuthVarianceState& state, bool pop)
 static DecimalV2Value decimalv2_compute_knuth_variance(const DecimalV2KnuthVarianceState& state,
                                                        bool pop) {
     DecimalV2Value new_count = DecimalV2Value();
-    new_count.assign_from_double(state.count);
     if (state.count == 1) return new_count;
+    new_count.assign_from_double(state.count);
     DecimalV2Value new_m2 = DecimalV2Value::from_decimal_val(state.m2);
     if (pop)
         return new_m2 / new_count;
@@ -2395,6 +2379,8 @@ template void AggregateFunctions::sum<IntVal, BigIntVal>(FunctionContext*, const
                                                          BigIntVal* dst);
 template void AggregateFunctions::sum<BigIntVal, BigIntVal>(FunctionContext*, const BigIntVal& src,
                                                             BigIntVal* dst);
+template void AggregateFunctions::sum<LargeIntVal, LargeIntVal>(FunctionContext*, const LargeIntVal& src,
+                                                            LargeIntVal* dst);
 template void AggregateFunctions::sum<FloatVal, DoubleVal>(FunctionContext*, const FloatVal& src,
                                                            DoubleVal* dst);
 template void AggregateFunctions::sum<DoubleVal, DoubleVal>(FunctionContext*, const DoubleVal& src,
diff --git a/be/src/exprs/math_functions.cpp b/be/src/exprs/math_functions.cpp
index 787887d..00cf3bd 100644
--- a/be/src/exprs/math_functions.cpp
+++ b/be/src/exprs/math_functions.cpp
@@ -178,11 +178,11 @@ ONE_ARG_MATH_FN(ln, DoubleVal, DoubleVal, std::log);
 ONE_ARG_MATH_FN(log10, DoubleVal, DoubleVal, std::log10);
 ONE_ARG_MATH_FN(exp, DoubleVal, DoubleVal, std::exp);
 
-FloatVal MathFunctions::sign(FunctionContext* ctx, const DoubleVal& v) {
+TinyIntVal MathFunctions::sign(FunctionContext* ctx, const DoubleVal& v) {
     if (v.is_null) {
-        return FloatVal::null();
+        return TinyIntVal::null();
     }
-    return FloatVal((v.val > 0) ? 1.0f : ((v.val < 0) ? -1.0f : 0.0f));
+    return TinyIntVal((v.val > 0) ? 1 : ((v.val < 0) ? -1 : 0));
 }
 
 DoubleVal MathFunctions::radians(FunctionContext* ctx, const DoubleVal& v) {
diff --git a/be/src/exprs/math_functions.h b/be/src/exprs/math_functions.h
index 5d1258e..9d55ed6 100644
--- a/be/src/exprs/math_functions.h
+++ b/be/src/exprs/math_functions.h
@@ -50,7 +50,8 @@ public:
     static doris_udf::IntVal abs(doris_udf::FunctionContext*, const doris_udf::SmallIntVal&);
     static doris_udf::SmallIntVal abs(doris_udf::FunctionContext*, const doris_udf::TinyIntVal&);
 
-    static doris_udf::FloatVal sign(doris_udf::FunctionContext* ctx, const doris_udf::DoubleVal& v);
+    static doris_udf::TinyIntVal sign(doris_udf::FunctionContext* ctx,
+                                      const doris_udf::DoubleVal& v);
 
     static doris_udf::DoubleVal sin(doris_udf::FunctionContext*, const doris_udf::DoubleVal&);
     static doris_udf::DoubleVal asin(doris_udf::FunctionContext*, const doris_udf::DoubleVal&);
@@ -182,11 +183,6 @@ public:
 
     static double my_double_round(double value, int64_t dec, bool dec_unsigned, bool truncate);
 
-private:
-    static const int32_t MIN_BASE = 2;
-    static const int32_t MAX_BASE = 36;
-    static const char* _s_alphanumeric_chars;
-
     // Converts src_num in decimal to dest_base,
     // and fills expr_val.string_val with the result.
     static doris_udf::StringVal decimal_to_base(doris_udf::FunctionContext* ctx, int64_t src_num,
@@ -207,6 +203,12 @@ private:
     // Returns false otherwise, indicating some other error condition.
     static bool handle_parse_result(int8_t dest_base, int64_t* num,
                                     StringParser::ParseResult parse_res);
+
+    static const int32_t MIN_BASE = 2;
+    static const int32_t MAX_BASE = 36;
+
+private:
+    static const char* _s_alphanumeric_chars;
 };
 
 } // namespace doris
diff --git a/be/src/exprs/runtime_filter.cpp b/be/src/exprs/runtime_filter.cpp
index b77cf9d..3cf45c4 100644
--- a/be/src/exprs/runtime_filter.cpp
+++ b/be/src/exprs/runtime_filter.cpp
@@ -373,6 +373,35 @@ public:
             break;
         }
     }
+    void insert(const StringRef& value) {
+        switch (_column_return_type) {
+        case TYPE_DATE:
+        case TYPE_DATETIME: {
+            // DateTime->DateTimeValue
+            vectorized::DateTime date_time =*reinterpret_cast<const vectorized::DateTime*>(value.data);
+            vectorized::VecDateTimeValue vec_date_time_value = binary_cast<vectorized::Int64, vectorized::VecDateTimeValue>(date_time);
+            doris::DateTimeValue date_time_value;
+            vec_date_time_value.convert_vec_dt_to_dt(&date_time_value);
+            insert(reinterpret_cast<const void*>(&date_time_value));
+            break;
+        }
+
+        case TYPE_CHAR:
+        case TYPE_VARCHAR:
+        case TYPE_HLL:
+        case TYPE_OBJECT:
+        case TYPE_STRING: {
+            // StringRef->StringValue
+            StringValue data = StringValue(const_cast<char*>(value.data), value.size);
+            insert(reinterpret_cast<const void*>(&data));
+            break;
+        }
+
+        default:
+            insert(reinterpret_cast<const void*>(value.data));
+            break;
+        }
+    }
 
     template <class T>
     Status get_push_context(T* container, RuntimeState* state, ExprContext* prob_expr) {
@@ -784,6 +813,11 @@ void IRuntimeFilter::insert(const void* data) {
     }
 }
 
+void IRuntimeFilter::insert(const StringRef& value) {
+    DCHECK(is_producer());
+    _wrapper->insert(value);
+}
+
 Status IRuntimeFilter::publish() {
     DCHECK(is_producer());
     if (_has_local_target) {
diff --git a/be/src/exprs/runtime_filter.h b/be/src/exprs/runtime_filter.h
index 7d406f3..c5e597a 100644
--- a/be/src/exprs/runtime_filter.h
+++ b/be/src/exprs/runtime_filter.h
@@ -128,6 +128,7 @@ public:
     // insert data to build filter
     // only used for producer
     void insert(const void* data);
+    void insert(const StringRef& data);
 
     // publish filter
     // push filter to remote node or push down it to scan_node
diff --git a/be/src/exprs/runtime_filter_slots.h b/be/src/exprs/runtime_filter_slots.h
index 576cad0..e098adc 100644
--- a/be/src/exprs/runtime_filter_slots.h
+++ b/be/src/exprs/runtime_filter_slots.h
@@ -20,9 +20,9 @@
 #include "exprs/runtime_filter.h"
 #include "runtime/runtime_filter_mgr.h"
 #include "runtime/runtime_state.h"
+#include "vec/exprs/vexpr.h"
 
 namespace doris {
-
 // this class used in a hash join node
 // Provide a unified interface for other classes
 template <typename ExprCtxType>
@@ -129,6 +129,40 @@ public:
             }
         }
     }
+    void insert(std::unordered_map<const vectorized::Block*, std::vector<int>>& datas) {
+        for (int i = 0; i < _build_expr_context.size(); ++i) {
+            auto iter = _runtime_filters.find(i);
+            if (iter == _runtime_filters.end()) continue;
+
+            int result_column_id = _build_expr_context[i]->get_last_result_column_id();
+            for (auto it : datas) {
+                auto& column = it.first->get_by_position(result_column_id).column;
+
+                if (auto* nullable =
+                            vectorized::check_and_get_column<vectorized::ColumnNullable>(*column)) {
+                    auto& column_nested = nullable->get_nested_column();
+                    auto& column_nullmap = nullable->get_null_map_column();
+                    for (int row_num : it.second) {
+                        if (column_nullmap.get_bool(row_num)) {
+                            continue;
+                        }
+                        const auto& ref_data = column_nested.get_data_at(row_num);
+                        for (auto filter : iter->second) {
+                            filter->insert(ref_data);
+                        }
+                    }
+
+                } else {
+                    for (int row_num : it.second) {
+                        const auto& ref_data = column->get_data_at(row_num);
+                        for (auto filter : iter->second) {
+                            filter->insert(ref_data);
+                        }
+                    }
+                }
+            }
+        }
+    }
 
     // should call this method after insert
     void ready_for_publish() {
@@ -166,5 +200,5 @@ private:
 };
 
 using RuntimeFilterSlots = RuntimeFilterSlotsBase<ExprContext>;
-
+using VRuntimeFilterSlots = RuntimeFilterSlotsBase<vectorized::VExprContext>;
 } // namespace doris
diff --git a/be/src/exprs/v_string_functions.h b/be/src/exprs/v_string_functions.h
new file mode 100644
index 0000000..3fd9845
--- /dev/null
+++ b/be/src/exprs/v_string_functions.h
@@ -0,0 +1,219 @@
+// 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
+
+#ifndef BE_V_STRING_FUNCTIONS_H
+#define BE_V_STRING_FUNCTIONS_H
+
+#include <stdint.h>
+#include <unistd.h>
+#include "runtime/string_value.hpp"
+
+#ifdef __SSE2__
+#include <emmintrin.h>
+#endif
+
+namespace doris {
+class VStringFunctions {
+public:
+#ifdef __SSE2__
+    /// n equals to 16 chars length
+    static constexpr auto REGISTER_SIZE = sizeof(__m128i);
+#endif
+public:
+    static StringVal rtrim(const StringVal& str) {
+        if (str.is_null || str.len == 0) {
+            return str;
+        }
+        auto begin = 0;
+        auto end = str.len - 1;
+#ifdef __SSE2__
+        char blank = ' ';
+        const auto pattern =  _mm_set1_epi8(blank);
+        while (end - begin + 1 >= REGISTER_SIZE) {
+            const auto v_haystack = _mm_loadu_si128(reinterpret_cast<const __m128i *>(str.ptr + end + 1 - REGISTER_SIZE));
+            const auto v_against_pattern = _mm_cmpeq_epi8(v_haystack, pattern);
+            const auto mask = _mm_movemask_epi8(v_against_pattern);
+            int offset = __builtin_clz(~(mask << REGISTER_SIZE));
+            /// means not found
+            if (offset == 0)
+            {
+                return StringVal(str.ptr + begin, end - begin + 1);
+            } else {
+                end -= offset;
+            }
+        }
+#endif
+        while (end >= begin && str.ptr[end] == ' ') {
+            --end;
+        }
+        if (end < 0) {
+            return StringVal("");
+        }
+        return StringVal(str.ptr + begin, end - begin + 1);
+    }
+
+    static StringVal ltrim(const StringVal& str) {
+        if (str.is_null || str.len == 0) {
+            return str;
+        }
+        auto begin = 0;
+        auto end = str.len - 1;
+#ifdef __SSE2__
+        char blank = ' ';
+        const auto pattern =  _mm_set1_epi8(blank);
+        while (end - begin + 1 >= REGISTER_SIZE) {
+            const auto v_haystack = _mm_loadu_si128(reinterpret_cast<const __m128i *>(str.ptr + begin));
+            const auto v_against_pattern = _mm_cmpeq_epi8(v_haystack, pattern);
+            const auto mask = _mm_movemask_epi8(v_against_pattern);
+            const auto offset = __builtin_ctz(mask ^ 0xffff);
+            /// means not found
+            if (offset == 0)
+            {
+                return StringVal(str.ptr + begin, end - begin + 1);
+            } else if (offset > REGISTER_SIZE) {
+                begin += REGISTER_SIZE;
+            } else {
+                begin += offset;
+                return StringVal(str.ptr + begin, end - begin + 1);
+            }
+        }
+#endif
+        while (begin <= end && str.ptr[begin] == ' ') {
+            ++begin;
+        }
+        return StringVal(str.ptr + begin, end - begin + 1);
+    }
+
+    static StringVal trim(const StringVal& str) {
+        if (str.is_null || str.len == 0) {
+            return str;
+        }
+        return rtrim(ltrim(str));
+    }
+
+    static bool is_ascii(StringVal str) {
+    #ifdef __SSE2__
+        size_t i = 0;
+        __m128i binary_code = _mm_setzero_si128();
+        if (str.len >= REGISTER_SIZE) {
+            for (; i <= str.len - REGISTER_SIZE; i += REGISTER_SIZE) {
+                __m128i chars = _mm_loadu_si128((const __m128i*)(str.ptr + i));
+                binary_code = _mm_or_si128(binary_code, chars);
+            }
+        }
+        int mask = _mm_movemask_epi8(binary_code);
+
+        char or_code = 0;
+        for (; i < str.len; i++) {
+            or_code |= str.ptr[i];
+        }
+        mask |= (or_code & 0x80);
+
+        return !mask;
+    #else
+        char or_code = 0;
+        for (size_t i = 0; i < str.len; i++) {
+            or_code |= str.ptr[i];
+        }
+        return !(or_code & 0x80);
+    #endif
+    }
+
+    static void reverse(const StringVal& str, StringVal dst) {
+        if (str.is_null) {
+            dst.ptr = NULL;
+            return;
+        }
+        const bool is_ascii = VStringFunctions::is_ascii(str);
+        if (is_ascii) {
+            int64_t begin = 0;
+            int64_t end = str.len;
+            int64_t result_end = dst.len;
+    #if defined(__SSE2__)
+            const auto shuffle_array = _mm_set_epi64((__m64)0x00'01'02'03'04'05'06'07ull, (__m64)0x08'09'0a'0b'0c'0d'0e'0full);
+            for (; (begin + REGISTER_SIZE) < end; begin += REGISTER_SIZE) {
+                result_end -= REGISTER_SIZE;
+                _mm_storeu_si128((__m128i*)(dst.ptr + result_end),
+                                 _mm_shuffle_epi8(_mm_loadu_si128((__m128i*)(str.ptr + begin)), shuffle_array));
+            }
+    #endif
+            for (; begin < end; ++begin) {
+                --result_end;
+                dst.ptr[result_end] = str.ptr[begin];
+            }
+        } else {
+            for (size_t i = 0, char_size = 0; i < str.len; i += char_size) {
+                char_size = get_utf8_byte_length((unsigned)(str.ptr)[i]);
+                std::copy(str.ptr + i, str.ptr + i + char_size, dst.ptr + str.len - i - char_size);
+            }
+        }
+    }
+
+    static size_t get_utf8_byte_length(unsigned char byte) {
+        size_t char_size = 0;
+        if (byte >= 0xFC) {
+            char_size = 6;
+        } else if (byte >= 0xF8) {
+            char_size = 5;
+        } else if (byte >= 0xF0) {
+            char_size = 4;
+        } else if (byte >= 0xE0) {
+            char_size = 3;
+        } else if (byte >= 0xC0) {
+            char_size = 2;
+        } else {
+            char_size = 1;
+        }
+        return char_size;
+    }
+
+    static void hex_encode(const unsigned char* src_str, size_t length, char* dst_str) {
+        static constexpr auto hex_table = "0123456789ABCDEF";
+        auto src_str_end = src_str + length;
+
+#if defined(__SSE2__)
+        constexpr auto step = sizeof(uint64);
+        if (src_str + step < src_str_end) {
+            const auto hex_map = _mm_loadu_si128(reinterpret_cast<const __m128i *>(hex_table));
+            const auto mask_map = _mm_set1_epi8(0x0F);
+
+            do {
+                auto data = _mm_loadu_si64(src_str);
+                auto hex_loc = _mm_and_si128(_mm_unpacklo_epi8(_mm_srli_epi64(data, 4), data), mask_map);
+                _mm_storeu_si128(reinterpret_cast<__m128i *>(dst_str), _mm_shuffle_epi8(hex_map, hex_loc));
+
+                src_str += step;
+                dst_str += step * 2;
+            } while (src_str + step < src_str_end);
+        }
+#endif
+        char res[2];
+        // hex(str) str length is n, result must be 2 * n length
+        for (; src_str < src_str_end; src_str += 1, dst_str += 2) {
+            // low 4 bits
+            *(res + 1) = hex_table[src_str[0] & 0x0F];
+            // high 4 bits
+            *res = hex_table[(src_str[0] >> 4)];
+            std::copy(res, res + 2, dst_str);
+        }
+    }
+};
+}
+
+#endif //BE_V_STRING_FUNCTIONS_H
\ No newline at end of file
diff --git a/be/src/olap/block_column_predicate.cpp b/be/src/olap/block_column_predicate.cpp
index f460be5..725ebda 100644
--- a/be/src/olap/block_column_predicate.cpp
+++ b/be/src/olap/block_column_predicate.cpp
@@ -39,6 +39,30 @@ void SingleColumnBlockPredicate::evaluate_or(RowBlockV2 *block, uint16_t selecte
     _predicate->evaluate_or(&column_block, block->selection_vector(), selected_size, flags);
 }
 
+void SingleColumnBlockPredicate::evaluate(vectorized::MutableColumns& block, uint16_t* sel, uint16_t* selected_size) const {
+    auto column_id = _predicate->column_id();
+    auto& column = block[column_id];
+    _predicate->evaluate(*column, sel, selected_size);
+}
+ 
+void SingleColumnBlockPredicate::evaluate_and(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const {
+    auto column_id = _predicate->column_id();
+    auto& column = block[column_id];
+    _predicate->evaluate_and(*column, sel, selected_size, flags);
+}
+ 
+void SingleColumnBlockPredicate::evaluate_or(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const {
+    auto column_id = _predicate->column_id();
+    auto& column = block[column_id];
+    _predicate->evaluate_or(*column, sel, selected_size, flags);
+}
+ 
+void SingleColumnBlockPredicate::evaluate_vec(vectorized::MutableColumns& block, uint16_t size, bool* flags) const {
+    auto column_id = _predicate->column_id();
+    auto& column = block[column_id];
+    _predicate->evaluate_vec(*column, size, flags);
+}
+
 void OrBlockColumnPredicate::evaluate(RowBlockV2* block, uint16_t* selected_size) const {
     if (num_of_column_predicate() == 1) {
         _block_column_predicate_vec[0]->evaluate(block, selected_size);
@@ -60,12 +84,39 @@ void OrBlockColumnPredicate::evaluate(RowBlockV2* block, uint16_t* selected_size
     }
 }
 
+void OrBlockColumnPredicate::evaluate(vectorized::MutableColumns& block, uint16_t* sel, uint16_t* selected_size) const {
+    if (num_of_column_predicate() == 1) {
+        _block_column_predicate_vec[0]->evaluate(block, sel, selected_size);
+    } else {
+        bool ret_flags[*selected_size];
+        memset(ret_flags, false, *selected_size);
+        for (int i = 0; i < num_of_column_predicate(); ++i) {
+            auto column_predicate = _block_column_predicate_vec[i];
+            column_predicate->evaluate_or(block, sel, *selected_size, ret_flags);
+        }
+ 
+        uint16_t new_size = 0;
+        for (int i = 0; i < *selected_size; ++i) {
+            if (ret_flags[i]) {
+                sel[new_size++] = sel[i];
+            }
+        }
+        *selected_size = new_size;
+    }
+}
+
 void OrBlockColumnPredicate::evaluate_or(RowBlockV2 *block, uint16_t selected_size, bool* flags) const {
     for (auto block_column_predicate : _block_column_predicate_vec) {
         block_column_predicate->evaluate_or(block, selected_size, flags);
     }
 }
 
+void OrBlockColumnPredicate::evaluate_or(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const {
+    for (auto block_column_predicate : _block_column_predicate_vec) {
+        block_column_predicate->evaluate_or(block, sel, selected_size, flags);
+    }
+}
+
 void OrBlockColumnPredicate::evaluate_and(RowBlockV2 *block, uint16_t selected_size, bool* flags) const {
     if (num_of_column_predicate() == 1) {
         _block_column_predicate_vec[0]->evaluate_and(block, selected_size, flags);
@@ -83,18 +134,47 @@ void OrBlockColumnPredicate::evaluate_and(RowBlockV2 *block, uint16_t selected_s
     }
 }
 
+void OrBlockColumnPredicate::evaluate_and(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const {
+    if (num_of_column_predicate() == 1) {
+        _block_column_predicate_vec[0]->evaluate_and(block, sel, selected_size, flags);
+    } else {
+        bool ret_flags[selected_size];
+        memset(ret_flags, false, selected_size);
+        for (int i = 0; i < num_of_column_predicate(); ++i) {
+            auto column_predicate = _block_column_predicate_vec[i];
+            column_predicate->evaluate_or(block, sel, selected_size, ret_flags);
+        }
+ 
+        for (int i = 0; i < selected_size; ++i) {
+            flags[i] &= ret_flags[i];
+        }
+    }
+}
+
 void AndBlockColumnPredicate::evaluate(RowBlockV2* block, uint16_t* selected_size) const {
     for (auto block_column_predicate : _block_column_predicate_vec) {
         block_column_predicate->evaluate(block, selected_size);
     }
 }
 
+void AndBlockColumnPredicate::evaluate(vectorized::MutableColumns& block, uint16_t* sel, uint16_t* selected_size) const {
+    for (auto block_column_predicate : _block_column_predicate_vec) {
+        block_column_predicate->evaluate(block, sel, selected_size);
+    }
+}
+
 void AndBlockColumnPredicate::evaluate_and(RowBlockV2 *block, uint16_t selected_size, bool* flags) const {
     for (auto block_column_predicate : _block_column_predicate_vec) {
         block_column_predicate->evaluate_and(block, selected_size, flags);
     }
 }
 
+void AndBlockColumnPredicate::evaluate_and(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const {
+    for (auto block_column_predicate : _block_column_predicate_vec) {
+        block_column_predicate->evaluate_and(block, sel, selected_size, flags);
+    }
+}
+
 void AndBlockColumnPredicate::evaluate_or(RowBlockV2 *block, uint16_t selected_size, bool* flags) const {
     if (num_of_column_predicate() == 1) {
         _block_column_predicate_vec[0]->evaluate_or(block, selected_size, flags);
@@ -113,4 +193,38 @@ void AndBlockColumnPredicate::evaluate_or(RowBlockV2 *block, uint16_t selected_s
     }
 }
 
+void AndBlockColumnPredicate::evaluate_or(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const {
+    if (num_of_column_predicate() == 1) {
+        _block_column_predicate_vec[0]->evaluate_or(block, sel, selected_size, flags);
+    } else {
+        bool new_flags[selected_size];
+        memset(new_flags, true, selected_size);
+ 
+        for (auto block_column_predicate : _block_column_predicate_vec) {
+            block_column_predicate->evaluate_and(block, sel, selected_size, new_flags);
+        }
+ 
+        for (uint16_t i = 0; i < selected_size; i++) {
+            flags[i] |= new_flags[i];
+        }
+    }
+}
+ 
+// todo(wb) Can the 'and' of multiple bitmaps be vectorized?
+void AndBlockColumnPredicate::evaluate_vec(vectorized::MutableColumns& block, uint16_t size, bool* flags) const {
+    if (num_of_column_predicate() == 1) {
+        _block_column_predicate_vec[0]->evaluate_vec(block, size, flags);
+    } else {
+        bool new_flags[size];
+        for (auto block_column_predicate : _block_column_predicate_vec) {
+            memset(new_flags, true, size);
+            block_column_predicate->evaluate_vec(block, size, new_flags);
+ 
+            for (uint16_t j = 0; j < size; j++) {
+                flags[j] &= new_flags[j] ;
+            }
+        }
+    }
+}
+
 } // namespace doris
diff --git a/be/src/olap/block_column_predicate.h b/be/src/olap/block_column_predicate.h
index 4c06486..ef2a4ca 100644
--- a/be/src/olap/block_column_predicate.h
+++ b/be/src/olap/block_column_predicate.h
@@ -44,6 +44,12 @@ public:
     virtual void evaluate_or(RowBlockV2* block, uint16_t selected_size, bool* flags) const = 0;
 
     virtual void get_all_column_ids(std::set<ColumnId>& column_id_set) const = 0;
+
+    virtual void evaluate(vectorized::MutableColumns& block, uint16_t* sel, uint16_t* selected_size) const {};
+    virtual void evaluate_and(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const {};
+    virtual void evaluate_or(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const {};
+ 
+    virtual void evaluate_vec(vectorized::MutableColumns& block, uint16_t size, bool* flags) const {};
 };
 
 class SingleColumnBlockPredicate : public BlockColumnPredicate {
@@ -57,6 +63,13 @@ public:
     void get_all_column_ids(std::set<ColumnId>& column_id_set) const override {
         column_id_set.insert(_predicate->column_id());
     };
+
+    void evaluate(vectorized::MutableColumns& block, uint16_t* sel, uint16_t* selected_size) const override;
+    void evaluate_and(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const override;
+    void evaluate_or(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const override;
+ 
+    void evaluate_vec(vectorized::MutableColumns& block, uint16_t size, bool* flags) const override;
+
 private:
     const ColumnPredicate* _predicate;
 };
@@ -98,6 +111,12 @@ public:
     // 2.Do AND SEMANTICS in flags use 1 result to get proper select flags
     void evaluate_and(RowBlockV2* block, uint16_t selected_size, bool* flags) const override;
     void evaluate_or(RowBlockV2* block, uint16_t selected_size, bool* flags) const override;
+
+    void evaluate(vectorized::MutableColumns& block, uint16_t* sel, uint16_t* selected_size) const override;
+    void evaluate_and(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const override;
+    void evaluate_or(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const override;
+
+    // note(wb) we didnt't impelment evaluate_vec method here, because storage layer only support AND predicate now;
 };
 
 class AndBlockColumnPredicate : public MutilColumnBlockPredicate {
@@ -109,6 +128,13 @@ public:
     // 1.AndBlockColumnPredicate need evaluate all child BlockColumnPredicate AND SEMANTICS inside first
     // 2.Evaluate OR SEMANTICS in flags use 1 result to get proper select flags
     void evaluate_or(RowBlockV2* block, uint16_t selected_size, bool* flags) const override;
+
+    void evaluate(vectorized::MutableColumns& block, uint16_t* sel, uint16_t* selected_size) const override;
+    void evaluate_and(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const override;
+    void evaluate_or(vectorized::MutableColumns& block, uint16_t* sel, uint16_t selected_size, bool* flags) const override;
+
+    void evaluate_vec(vectorized::MutableColumns& block, uint16_t size, bool* flags) const override;
+
 };
 
 } //namespace doris
diff --git a/be/src/olap/bloom_filter_predicate.h b/be/src/olap/bloom_filter_predicate.h
index b3dcbbb..ff3201c 100644
--- a/be/src/olap/bloom_filter_predicate.h
+++ b/be/src/olap/bloom_filter_predicate.h
@@ -27,6 +27,10 @@
 #include "olap/field.h"
 #include "runtime/string_value.hpp"
 #include "runtime/vectorized_row_batch.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/columns/column_vector.h"
+#include "vec/columns/predicate_column.h"
+#include "vec/utils/util.hpp"
 
 namespace doris {
 
@@ -59,12 +63,14 @@ public:
         return Status::OK();
     }
 
+    void evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const override;
+
 private:
     std::shared_ptr<IBloomFilterFuncBase> _filter;
     SpecificFilter* _specific_filter; // owned by _filter
 };
 
-// blomm filter column predicate do not support in segment v1
+// bloom filter column predicate do not support in segment v1
 template <PrimitiveType type>
 void BloomFilterColumnPredicate<type>::evaluate(VectorizedRowBatch* batch) const {
     uint16_t n = batch->size();
@@ -99,6 +105,38 @@ void BloomFilterColumnPredicate<type>::evaluate(ColumnBlock* block, uint16_t* se
     *size = new_size;
 }
 
+template <PrimitiveType type>
+void BloomFilterColumnPredicate<type>::evaluate(vectorized::IColumn& column, uint16_t* sel,
+                                                uint16_t* size) const {
+    uint16_t new_size = 0;
+    using T = typename PrimitiveTypeTraits<type>::CppType;
+
+    if (column.is_nullable()) {
+        auto* nullable_col = vectorized::check_and_get_column<vectorized::ColumnNullable>(column);
+        auto& null_map_data = nullable_col->get_null_map_column().get_data();
+        auto* pred_col = vectorized::check_and_get_column<vectorized::PredicateColumnType<T>>(
+                nullable_col->get_nested_column());
+        auto& pred_col_data = pred_col->get_data();
+        for (uint16_t i = 0; i < *size; i++) {
+            uint16_t idx = sel[i];
+            sel[new_size] = idx;
+            const auto* cell_value = reinterpret_cast<const void*>(&(pred_col_data[idx]));
+            new_size += (!null_map_data[idx]) && _specific_filter->find_olap_engine(cell_value);
+        }
+    } else {
+        auto* pred_col =
+                vectorized::check_and_get_column<vectorized::PredicateColumnType<T>>(column);
+        auto& pred_col_data = pred_col->get_data();
+        for (uint16_t i = 0; i < *size; i++) {
+            uint16_t idx = sel[i];
+            sel[new_size] = idx;
+            const auto* cell_value = reinterpret_cast<const void*>(&(pred_col_data[idx]));
+            new_size += _specific_filter->find_olap_engine(cell_value);
+        }
+    }
+    *size = new_size;
+}
+
 class BloomFilterColumnPredicateFactory {
 public:
     static ColumnPredicate* create_column_predicate(
diff --git a/be/src/olap/collect_iterator.cpp b/be/src/olap/collect_iterator.cpp
index 903ed0a..46a7aa4 100644
--- a/be/src/olap/collect_iterator.cpp
+++ b/be/src/olap/collect_iterator.cpp
@@ -32,7 +32,7 @@ CollectIterator::~CollectIterator() = default;
 void CollectIterator::init(TabletReader* reader) {
     _reader = reader;
     // when aggregate is enabled or key_type is DUP_KEYS, we don't merge
-    // multiple data to aggregate for performance in user fetch
+    // multiple data to aggregate for better performance
     if (_reader->_reader_type == READER_QUERY &&
         (_reader->_aggregation || _reader->_tablet->keys_type() == KeysType::DUP_KEYS)) {
         _merge = false;
diff --git a/be/src/olap/column_predicate.h b/be/src/olap/column_predicate.h
index 21b115e..6b1aa23 100644
--- a/be/src/olap/column_predicate.h
+++ b/be/src/olap/column_predicate.h
@@ -23,6 +23,7 @@
 #include "olap/column_block.h"
 #include "olap/rowset/segment_v2/bitmap_index_reader.h"
 #include "olap/selection_vector.h"
+#include "vec/columns/column.h"
 
 using namespace doris::segment_v2;
 
@@ -54,8 +55,22 @@ public:
                             const std::vector<BitmapIndexIterator*>& iterators, uint32_t num_rows,
                             roaring::Roaring* roaring) const = 0;
 
+    // evaluate predicate on IColumn
+    // a short circuit eval way
+    virtual void evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const {};
+    virtual void evaluate_and(vectorized::IColumn& column, uint16_t* sel, uint16_t size,
+                              bool* flags) const {};
+    virtual void evaluate_or(vectorized::IColumn& column, uint16_t* sel, uint16_t size,
+                             bool* flags) const {};
+
+    // used to evaluate pre read column in lazy matertialization
+    // now only support integer/float
+    // a vectorized eval way
+    virtual void evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags) const {};
     uint32_t column_id() const { return _column_id; }
 
+    virtual bool is_in_predicate() { return false; }
+
 protected:
     uint32_t _column_id;
     bool _opposite;
diff --git a/be/src/olap/comparison_predicate.cpp b/be/src/olap/comparison_predicate.cpp
index 7dbe7cb..a154a04 100644
--- a/be/src/olap/comparison_predicate.cpp
+++ b/be/src/olap/comparison_predicate.cpp
@@ -21,6 +21,9 @@
 #include "olap/schema.h"
 #include "runtime/string_value.hpp"
 #include "runtime/vectorized_row_batch.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/columns/column_vector.h"
+#include "vec/columns/predicate_column.h"
 
 namespace doris {
 
@@ -142,6 +145,75 @@ COMPARISON_PRED_COLUMN_BLOCK_EVALUATE(LessEqualPredicate, <=)
 COMPARISON_PRED_COLUMN_BLOCK_EVALUATE(GreaterPredicate, >)
 COMPARISON_PRED_COLUMN_BLOCK_EVALUATE(GreaterEqualPredicate, >=)
 
+#define COMPARISON_PRED_COLUMN_EVALUATE(CLASS, OP)                                                                                                    \
+    template <class type>                                                                                                                             \
+    void CLASS<type>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const {                                                    \
+        uint16_t new_size = 0;                                                                                                                        \
+        if (column.is_nullable()) {                                           \
+            auto* nullable_column = vectorized::check_and_get_column<vectorized::ColumnNullable>(column);\
+            auto& null_bitmap = reinterpret_cast<const vectorized::ColumnVector<uint8_t>&>(*(nullable_column->get_null_map_column_ptr())).get_data(); \
+            auto* nest_column_vector = vectorized::check_and_get_column<vectorized::PredicateColumnType<type>>(nullable_column->get_nested_column());\
+            auto& data_array = nest_column_vector->get_data();          \
+            for (uint16_t i = 0; i < *size; i++) {                                                                                                \
+                    uint16_t idx = sel[i];                                                                                                            \
+                    sel[new_size] = idx;                                                                                                              \
+                    const type& cell_value = reinterpret_cast<const type&>(data_array[idx]);                                                          \
+                    bool ret = !null_bitmap[idx] && (cell_value OP _value);                                                                            \
+                    new_size += _opposite ? !ret : ret;                                                                                               \
+            }                                                                                                                                     \
+            *size = new_size;                                                                                                                   \
+        } else {\
+            auto& pred_column_ref = reinterpret_cast<vectorized::PredicateColumnType<type>&>(column);\
+            auto& data_array = pred_column_ref.get_data();                                                                                             \
+            for (uint16_t i = 0; i < *size; i++) {                                                                                                    \
+                uint16_t idx = sel[i];                                                                                                                \
+                sel[new_size] = idx;                                                                                                                  \
+                const type& cell_value = reinterpret_cast<const type&>(data_array[idx]);                                                              \
+                auto ret = cell_value OP _value;                                                                                                      \
+                new_size += _opposite ? !ret : ret;                                                                                                   \
+            }                                                                                                                                         \
+            *size = new_size;   \
+        }\
+    }
+ 
+COMPARISON_PRED_COLUMN_EVALUATE(EqualPredicate, ==)
+COMPARISON_PRED_COLUMN_EVALUATE(NotEqualPredicate, !=)
+COMPARISON_PRED_COLUMN_EVALUATE(LessPredicate, <)
+COMPARISON_PRED_COLUMN_EVALUATE(LessEqualPredicate, <=)
+COMPARISON_PRED_COLUMN_EVALUATE(GreaterPredicate, >)
+COMPARISON_PRED_COLUMN_EVALUATE(GreaterEqualPredicate, >=)
+ 
+#define COMPARISON_PRED_COLUMN_EVALUATE_VEC(CLASS, OP)                                                                                                \
+    template <class type>                                                                                                                             \
+    void CLASS<type>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags) const {                                                   \
+        if (column.is_nullable()) {                                                                                                                   \
+            auto* nullable_column = vectorized::check_and_get_column<vectorized::ColumnNullable>(column);                                             \
+            auto& data_array = reinterpret_cast<const vectorized::PredicateColumnType<type>&>(nullable_column->get_nested_column()).get_data();              \
+            auto& null_bitmap = reinterpret_cast<const vectorized::ColumnVector<uint8_t>&>(*(nullable_column->get_null_map_column_ptr())).get_data(); \
+            for (uint16_t i = 0; i < size; i++) {                                                                                                     \
+                flags[i] = (data_array[i] OP _value) && (!null_bitmap[i]);                                                                            \
+            }                                                                                                                                         \
+        } else {                                                                                                                                      \
+            auto& predicate_column = reinterpret_cast<vectorized::PredicateColumnType<type>&>(column);                                                \
+            auto& data_array = predicate_column.get_data();                                                                                           \
+            for (uint16_t i = 0; i < size; i++) {                                                                                                     \
+                flags[i] = data_array[i] OP _value;                                                                                                   \
+            }                                                                                                                                         \
+        }                                                                                                                                             \
+        if (_opposite) {                                                                                                                              \
+            for (uint16_t i = 0; i < size; i++) {                                                                                                     \
+                flags[i] = !flags[i];                                                                                                                 \
+            }                                                                                                                                         \
+        }                                                                                                                                             \
+    }
+ 
+COMPARISON_PRED_COLUMN_EVALUATE_VEC(EqualPredicate, ==)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC(NotEqualPredicate, !=)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC(LessPredicate, <)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC(LessEqualPredicate, <=)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC(GreaterPredicate, >)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC(GreaterEqualPredicate, >=)
+
 #define COMPARISON_PRED_COLUMN_BLOCK_EVALUATE_OR(CLASS, OP)                                      \
     template <class type>                                                                        \
     void CLASS<type>::evaluate_or(ColumnBlock* block, uint16_t* sel, uint16_t size, bool* flags) \
@@ -174,6 +246,20 @@ COMPARISON_PRED_COLUMN_BLOCK_EVALUATE_OR(LessEqualPredicate, <=)
 COMPARISON_PRED_COLUMN_BLOCK_EVALUATE_OR(GreaterPredicate, >)
 COMPARISON_PRED_COLUMN_BLOCK_EVALUATE_OR(GreaterEqualPredicate, >=)
 
+// todo(wb) support it
+#define COMPARISON_PRED_COLUMN_EVALUATE_OR(CLASS, OP)                                  \
+    template <class type>                                                                 \
+    void CLASS<type>::evaluate_or(vectorized::IColumn& column, uint16_t* sel, uint16_t size, bool* flags) const { \
+                                                               \
+    }
+ 
+COMPARISON_PRED_COLUMN_EVALUATE_OR(EqualPredicate, ==)
+COMPARISON_PRED_COLUMN_EVALUATE_OR(NotEqualPredicate, !=)
+COMPARISON_PRED_COLUMN_EVALUATE_OR(LessPredicate, <)
+COMPARISON_PRED_COLUMN_EVALUATE_OR(LessEqualPredicate, <=)
+COMPARISON_PRED_COLUMN_EVALUATE_OR(GreaterPredicate, >)
+COMPARISON_PRED_COLUMN_EVALUATE_OR(GreaterEqualPredicate, >=)
+
 #define COMPARISON_PRED_COLUMN_BLOCK_EVALUATE_AND(CLASS, OP)                                      \
     template <class type>                                                                         \
     void CLASS<type>::evaluate_and(ColumnBlock* block, uint16_t* sel, uint16_t size, bool* flags) \
@@ -206,6 +292,21 @@ COMPARISON_PRED_COLUMN_BLOCK_EVALUATE_AND(LessEqualPredicate, <=)
 COMPARISON_PRED_COLUMN_BLOCK_EVALUATE_AND(GreaterPredicate, >)
 COMPARISON_PRED_COLUMN_BLOCK_EVALUATE_AND(GreaterEqualPredicate, >=)
 
+//todo(wb) support it
+#define COMPARISON_PRED_COLUMN_EVALUATE_AND(CLASS, OP)                                  \
+    template <class type>                                                                 \
+    void CLASS<type>::evaluate_and(vectorized::IColumn& column, uint16_t* sel, uint16_t size, bool* flags) const { \
+                                                               \
+                                                                               \
+    }
+ 
+COMPARISON_PRED_COLUMN_EVALUATE_AND(EqualPredicate, ==)
+COMPARISON_PRED_COLUMN_EVALUATE_AND(NotEqualPredicate, !=)
+COMPARISON_PRED_COLUMN_EVALUATE_AND(LessPredicate, <)
+COMPARISON_PRED_COLUMN_EVALUATE_AND(LessEqualPredicate, <=)
+COMPARISON_PRED_COLUMN_EVALUATE_AND(GreaterPredicate, >)
+COMPARISON_PRED_COLUMN_EVALUATE_AND(GreaterEqualPredicate, >=)
+
 #define BITMAP_COMPARE_EqualPredicate(s, exact_match, seeked_ordinal, iterator, bitmap, roaring) \
     do {                                                                                         \
         if (!s.is_not_found()) {                                                                 \
@@ -440,4 +541,66 @@ COMPARISON_PRED_BITMAP_EVALUATE_DECLARATION(LessEqualPredicate)
 COMPARISON_PRED_BITMAP_EVALUATE_DECLARATION(GreaterPredicate)
 COMPARISON_PRED_BITMAP_EVALUATE_DECLARATION(GreaterEqualPredicate)
 
+#define COMPARISON_PRED_COLUMN_EVALUATE_DECLARATION(CLASS)                                                  \
+    template void CLASS<int8_t>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)       \
+            const;                                                                                          \
+    template void CLASS<int16_t>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)      \
+            const;                                                                                          \
+    template void CLASS<int32_t>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)      \
+            const;                                                                                          \
+    template void CLASS<int64_t>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)      \
+            const;                                                                                          \
+    template void CLASS<int128_t>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)     \
+            const;                                                                                          \
+    template void CLASS<float>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const; \
+    template void CLASS<double>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)       \
+            const;                                                                                          \
+    template void CLASS<decimal12_t>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)  \
+            const;                                                                                          \
+    template void CLASS<StringValue>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)  \
+            const;                                                                                          \
+    template void CLASS<uint24_t>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)     \
+            const;                                                                                          \
+    template void CLASS<uint64_t>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size)     \
+            const;                                                                                          \
+    template void CLASS<bool>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const;
+ 
+COMPARISON_PRED_COLUMN_EVALUATE_DECLARATION(EqualPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_DECLARATION(NotEqualPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_DECLARATION(LessPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_DECLARATION(LessEqualPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_DECLARATION(GreaterPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_DECLARATION(GreaterEqualPredicate)
+ 
+#define COMPARISON_PRED_COLUMN_EVALUATE_VEC_DECLARATION(CLASS)                                                  \
+    template void CLASS<int8_t>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)       \
+            const;                                                                                          \
+    template void CLASS<int16_t>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)      \
+            const;                                                                                          \
+    template void CLASS<int32_t>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)      \
+            const;                                                                                          \
+    template void CLASS<int64_t>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)      \
+            const;                                                                                          \
+    template void CLASS<int128_t>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)     \
+            const;                                                                                          \
+    template void CLASS<float>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags) const; \
+    template void CLASS<double>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)       \
+            const;                                                                                          \
+    template void CLASS<decimal12_t>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)  \
+            const;                                                                                          \
+    template void CLASS<StringValue>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)  \
+            const;                                                                                          \
+    template void CLASS<uint24_t>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)     \
+            const;                                                                                          \
+    template void CLASS<uint64_t>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags)     \
+            const;                                                                                          \
+    template void CLASS<bool>::evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags) const;
+ 
+COMPARISON_PRED_COLUMN_EVALUATE_VEC_DECLARATION(EqualPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC_DECLARATION(NotEqualPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC_DECLARATION(LessPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC_DECLARATION(LessEqualPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC_DECLARATION(GreaterPredicate)
+COMPARISON_PRED_COLUMN_EVALUATE_VEC_DECLARATION(GreaterEqualPredicate)
+
 } //namespace doris
diff --git a/be/src/olap/comparison_predicate.h b/be/src/olap/comparison_predicate.h
index d0a4049..30fd9fd 100644
--- a/be/src/olap/comparison_predicate.h
+++ b/be/src/olap/comparison_predicate.h
@@ -40,6 +40,10 @@ class VectorizedRowBatch;
         virtual Status evaluate(const Schema& schema,                                         \
                                 const std::vector<BitmapIndexIterator*>& iterators,           \
                                 uint32_t num_rows, roaring::Roaring* roaring) const override; \
+        void evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const override; \
+        void evaluate_and(vectorized::IColumn& column, uint16_t* sel, uint16_t size, bool* flags) const override; \
+        void evaluate_or(vectorized::IColumn& column, uint16_t* sel, uint16_t size, bool* flags) const override; \
+        void evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags) const override; \
                                                                                               \
     private:                                                                                  \
         type _value;                                                                          \
diff --git a/be/src/olap/generic_iterators.cpp b/be/src/olap/generic_iterators.cpp
index adac5df..8a11108 100644
--- a/be/src/olap/generic_iterators.cpp
+++ b/be/src/olap/generic_iterators.cpp
@@ -116,6 +116,11 @@ public:
     MergeIteratorContext(RowwiseIterator* iter, std::shared_ptr<MemTracker> parent)
             : _iter(iter), _block(iter->schema(), 1024, std::move(parent)) {}
 
+    MergeIteratorContext(const MergeIteratorContext&) = delete;
+    MergeIteratorContext(MergeIteratorContext&&) = delete;
+    MergeIteratorContext& operator=(const MergeIteratorContext&) = delete;
+    MergeIteratorContext& operator=(MergeIteratorContext&&) = delete;
+
     ~MergeIteratorContext() {
         delete _iter;
         _iter = nullptr;
@@ -151,6 +156,7 @@ private:
 
 private:
     RowwiseIterator* _iter;
+
     // used to store data load from iterator
     RowBlockV2 _block;
 
@@ -181,10 +187,9 @@ Status MergeIteratorContext::advance() {
 }
 
 Status MergeIteratorContext::_load_next_block() {
-    Status st;
     do {
         _block.clear();
-        st = _iter->next_batch(&_block);
+        Status st = _iter->next_batch(&_block);
         if (!st.ok()) {
             _valid = false;
             if (st.is_end_of_file()) {
@@ -202,27 +207,29 @@ Status MergeIteratorContext::_load_next_block() {
 class MergeIterator : public RowwiseIterator {
 public:
     // MergeIterator takes the ownership of input iterators
-    MergeIterator(std::list<RowwiseIterator*> iters, std::shared_ptr<MemTracker> parent, int sequence_id_idx)
-        : _origin_iters(std::move(iters)), _sequence_id_idx(sequence_id_idx) {
+    MergeIterator(std::vector<RowwiseIterator*> iters, std::shared_ptr<MemTracker> parent, int sequence_id_idx)
+        : _origin_iters(std::move(iters)), _sequence_id_idx(sequence_id_idx), _merge_heap(MergeContextComparator(_sequence_id_idx)) {
         // use for count the mem use of Block use in Merge
         _mem_tracker = MemTracker::CreateTracker(-1, "MergeIterator", parent, false);
     }
 
     ~MergeIterator() override {
-        while (!_merge_heap->empty()) {
-            auto ctx = _merge_heap->top();
-            _merge_heap->pop();
+        while (!_merge_heap.empty()) {
+            auto ctx = _merge_heap.top();
+            _merge_heap.pop();
             delete ctx;
         }
     }
+
     Status init(const StorageReadOptions& opts) override;
+
     Status next_batch(RowBlockV2* block) override;
 
     const Schema& schema() const override { return *_schema; }
 
 private:
     // It will be released after '_merge_heap' has been built.
-    std::list<RowwiseIterator*> _origin_iters;
+    std::vector<RowwiseIterator*> _origin_iters;
 
     int _sequence_id_idx;
 
@@ -256,9 +263,12 @@ private:
 
         int sequence_id_idx;
     };
-    using MergeHeap = std::priority_queue<MergeIteratorContext*, std::vector<MergeIteratorContext*>,
-                                          MergeContextComparator>;
-    std::unique_ptr<MergeHeap> _merge_heap;
+
+    using MergeHeap = std::priority_queue<MergeIteratorContext*, 
+                                        std::vector<MergeIteratorContext*>,
+                                        MergeContextComparator>;
+
+    MergeHeap _merge_heap;
 };
 
 Status MergeIterator::init(const StorageReadOptions& opts) {
@@ -267,24 +277,24 @@ Status MergeIterator::init(const StorageReadOptions& opts) {
     }
     _schema.reset(new Schema((*(_origin_iters.begin()))->schema()));
 
-    _merge_heap = std::make_unique<MergeHeap>(MergeContextComparator(_sequence_id_idx));
     for (auto iter : _origin_iters) {
         std::unique_ptr<MergeIteratorContext> ctx(new MergeIteratorContext(iter, _mem_tracker));
         RETURN_IF_ERROR(ctx->init(opts));
         if (!ctx->valid()) {
             continue;
         }
-        _merge_heap->push(ctx.release());
+        _merge_heap.push(ctx.release());
     }
+
     _origin_iters.clear();
     return Status::OK();
 }
 
 Status MergeIterator::next_batch(RowBlockV2* block) {
     size_t row_idx = 0;
-    for (; row_idx < block->capacity() && !_merge_heap->empty(); ++row_idx) {
-        auto ctx = _merge_heap->top();
-        _merge_heap->pop();
+    for (; row_idx < block->capacity() && !_merge_heap.empty(); ++row_idx) {
+        auto ctx = _merge_heap.top();
+        _merge_heap.pop();
 
         RowBlockRow dst_row = block->row(row_idx);
         // copy current row to block
@@ -292,7 +302,7 @@ Status MergeIterator::next_batch(RowBlockV2* block) {
 
         RETURN_IF_ERROR(ctx->advance());
         if (ctx->valid()) {
-            _merge_heap->push(ctx);
+            _merge_heap.push(ctx);
         } else {
             // Release ctx earlier to reduce resource consumed
             delete ctx;
@@ -313,17 +323,17 @@ public:
     // Iterators' ownership it transfered to this class.
     // This class will delete all iterators when destructs
     // Client should not use iterators any more.
-    UnionIterator(std::list<RowwiseIterator*> iters, std::shared_ptr<MemTracker> parent)
-            : _origin_iters(std::move(iters)) {
+    UnionIterator(std::vector<RowwiseIterator*> &v, std::shared_ptr<MemTracker> parent)
+            : _origin_iters(v.begin(), v.end()) {
         _mem_tracker = MemTracker::CreateTracker(-1, "UnionIterator", parent, false);
     }
 
     ~UnionIterator() override {
-        for (auto iter : _origin_iters) {
-            delete iter;
-        }
+        std::for_each(_origin_iters.begin(), _origin_iters.end(), std::default_delete<RowwiseIterator>());
     }
+
     Status init(const StorageReadOptions& opts) override;
+
     Status next_batch(RowBlockV2* block) override;
 
     const Schema& schema() const override { return *_schema; }
@@ -331,7 +341,7 @@ public:
 private:
     std::unique_ptr<Schema> _schema;
     RowwiseIterator* _cur_iter = nullptr;
-    std::list<RowwiseIterator*> _origin_iters;
+    std::deque<RowwiseIterator*> _origin_iters;
 };
 
 Status UnionIterator::init(const StorageReadOptions& opts) {
@@ -364,18 +374,18 @@ Status UnionIterator::next_batch(RowBlockV2* block) {
     return Status::EndOfFile("End of UnionIterator");
 }
 
-RowwiseIterator* new_merge_iterator(std::list<RowwiseIterator*> inputs, std::shared_ptr<MemTracker> parent, int sequence_id_idx) {
+RowwiseIterator* new_merge_iterator(std::vector<RowwiseIterator*> inputs, std::shared_ptr<MemTracker> parent, int sequence_id_idx) {
     if (inputs.size() == 1) {
         return *(inputs.begin());
     }
     return new MergeIterator(std::move(inputs), parent, sequence_id_idx);
 }
 
-RowwiseIterator* new_union_iterator(std::list<RowwiseIterator*> inputs, std::shared_ptr<MemTracker> parent) {
+RowwiseIterator* new_union_iterator(std::vector<RowwiseIterator*>& inputs, std::shared_ptr<MemTracker> parent) {
     if (inputs.size() == 1) {
         return *(inputs.begin());
     }
-    return new UnionIterator(std::move(inputs), parent);
+    return new UnionIterator(inputs, parent);
 }
 
 RowwiseIterator* new_auto_increment_iterator(const Schema& schema, size_t num_rows) {
diff --git a/be/src/olap/generic_iterators.h b/be/src/olap/generic_iterators.h
index 1d3eccf..e8f4528 100644
--- a/be/src/olap/generic_iterators.h
+++ b/be/src/olap/generic_iterators.h
@@ -25,14 +25,14 @@ namespace doris {
 //
 // Inputs iterators' ownership is taken by created merge iterator. And client
 // should delete returned iterator after usage.
-RowwiseIterator* new_merge_iterator(std::list<RowwiseIterator*> inputs, std::shared_ptr<MemTracker> parent, int sequence_id_idx);
+RowwiseIterator* new_merge_iterator(std::vector<RowwiseIterator*> inputs, std::shared_ptr<MemTracker> parent, int sequence_id_idx);
 
 // Create a union iterator for input iterators. Union iterator will read
 // input iterators one by one.
 //
 // Inputs iterators' ownership is taken by created union iterator. And client
 // should delete returned iterator after usage.
-RowwiseIterator* new_union_iterator(std::list<RowwiseIterator*> inputs, std::shared_ptr<MemTracker> parent);
+RowwiseIterator* new_union_iterator(std::vector<RowwiseIterator*>& inputs, std::shared_ptr<MemTracker> parent);
 
 // Create an auto increment iterator which returns num_rows data in format of schema.
 // This class aims to be used in unit test.
diff --git a/be/src/olap/in_list_predicate.cpp b/be/src/olap/in_list_predicate.cpp
index c167a17..a17e157 100644
--- a/be/src/olap/in_list_predicate.cpp
+++ b/be/src/olap/in_list_predicate.cpp
@@ -20,6 +20,8 @@
 #include "olap/field.h"
 #include "runtime/string_value.hpp"
 #include "runtime/vectorized_row_batch.h"
+#include "vec/columns/predicate_column.h"
+#include "vec/columns/column_nullable.h"
 
 namespace doris {
 
@@ -115,6 +117,43 @@ IN_LIST_PRED_EVALUATE(NotInListPredicate, ==)
 IN_LIST_PRED_COLUMN_BLOCK_EVALUATE(InListPredicate, !=)
 IN_LIST_PRED_COLUMN_BLOCK_EVALUATE(NotInListPredicate, ==)
 
+#define IN_LIST_PRED_COLUMN_EVALUATE(CLASS, OP)                                                    \
+    template <class type>                                                                          \
+    void CLASS<type>::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const { \
+        uint16_t new_size = 0;                                                                     \
+        if (column.is_nullable()) {                                                                \
+            auto* nullable_column =                                                                \
+                vectorized::check_and_get_column<vectorized::ColumnNullable>(column);              \
+            auto& null_bitmap = reinterpret_cast<const vectorized::ColumnVector<uint8_t>&>(*(      \
+                nullable_column->get_null_map_column_ptr())).get_data();                           \
+            auto* nest_column_vector = vectorized::check_and_get_column                            \
+                <vectorized::PredicateColumnType<type>>(nullable_column->get_nested_column());     \
+            auto& data_array = nest_column_vector->get_data();                                     \
+            for (uint16_t i = 0; i < *size; i++) {                                                 \
+                uint16_t idx = sel[i];                                                             \
+                sel[new_size] = idx;                                                               \
+                const type& cell_value = reinterpret_cast<const type&>(data_array[idx]);           \
+                bool ret = !null_bitmap[idx] && (_values.find(cell_value) OP _values.end());       \
+                new_size += _opposite ? !ret : ret;                                                \
+            }                                                                                      \
+            *size = new_size;                                                                      \
+        } else {                                                                                   \
+            auto& number_column = reinterpret_cast<vectorized::PredicateColumnType<type>&>(column);\
+            auto& data_array = number_column.get_data();                                           \
+            for (uint16_t i = 0; i < *size; i++) {                                                 \
+                uint16_t idx = sel[i];                                                             \
+                sel[new_size] = idx;                                                               \
+                const type& cell_value = reinterpret_cast<const type&>(data_array[idx]);           \
+                auto result = (_values.find(cell_value) OP _values.end());                         \
+                new_size += _opposite ? !result : result;                                          \
+            }                                                                                      \
+        }                                                                                          \
+        *size = new_size;                                                                          \
+    }
+
+IN_LIST_PRED_COLUMN_EVALUATE(InListPredicate, !=)
+IN_LIST_PRED_COLUMN_EVALUATE(NotInListPredicate, ==)
+
 #define IN_LIST_PRED_COLUMN_BLOCK_EVALUATE_OR(CLASS, OP)                                         \
     template <class type>                                                                        \
     void CLASS<type>::evaluate_or(ColumnBlock* block, uint16_t* sel, uint16_t size, bool* flags) \
diff --git a/be/src/olap/in_list_predicate.h b/be/src/olap/in_list_predicate.h
index cf9bf61..7cd237b 100644
--- a/be/src/olap/in_list_predicate.h
+++ b/be/src/olap/in_list_predicate.h
@@ -76,6 +76,8 @@ namespace doris {
 
 class VectorizedRowBatch;
 
+// todo(wb) support evaluate_and,evaluate_or
+
 #define IN_LIST_PRED_CLASS_DEFINE(CLASS)                                                          \
     template <class type>                                                                         \
     class CLASS : public ColumnPredicate {                                                        \
@@ -90,7 +92,10 @@ class VectorizedRowBatch;
         virtual Status evaluate(const Schema& schema,                                             \
                                 const std::vector<BitmapIndexIterator*>& iterators,               \
                                 uint32_t num_rows, roaring::Roaring* bitmap) const override;      \
-                                                                                                  \
+        void evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const override; \
+        void evaluate_and(vectorized::IColumn& column, uint16_t* sel, uint16_t size, bool* flags) const override {} \
+        void evaluate_or(vectorized::IColumn& column, uint16_t* sel, uint16_t size, bool* flags) const override {} \
+        bool is_in_predicate() override { return true; }                                                                                          \
     private:                                                                                      \
         phmap::flat_hash_set<type> _values;                                                       \
     };
diff --git a/be/src/olap/iterators.h b/be/src/olap/iterators.h
index d514dc0..4cdfc60 100644
--- a/be/src/olap/iterators.h
+++ b/be/src/olap/iterators.h
@@ -23,6 +23,7 @@
 #include "olap/olap_common.h"
 #include "olap/column_predicate.h"
 #include "olap/block_column_predicate.h"
+#include "vec/core/block.h"
 
 namespace doris {
 
@@ -80,6 +81,7 @@ public:
     // REQUIRED (null is not allowed)
     OlapReaderStatistics* stats = nullptr;
     bool use_page_cache = false;
+    int block_row_max = 4096;
 };
 
 // Used to read data in RowBlockV2 one by one
@@ -99,7 +101,9 @@ public:
     // into input batch with Status::OK() returned
     // If there is no data to read, will return Status::EndOfFile.
     // If other error happens, other error code will be returned.
-    virtual Status next_batch(RowBlockV2* block) = 0;
+    virtual Status next_batch(RowBlockV2* block) { return Status::NotSupported("to be implemented"); }
+
+    virtual Status next_batch(vectorized::Block* block) { return Status::NotSupported("to be implemented"); }
 
     // return schema for this Iterator
     virtual const Schema& schema() const = 0;
diff --git a/be/src/olap/null_predicate.cpp b/be/src/olap/null_predicate.cpp
index cc88d26..da3eb29 100644
--- a/be/src/olap/null_predicate.cpp
+++ b/be/src/olap/null_predicate.cpp
@@ -20,6 +20,9 @@
 #include "olap/field.h"
 #include "runtime/string_value.hpp"
 #include "runtime/vectorized_row_batch.h"
+#include "vec/columns/column_nullable.h"
+
+using namespace doris::vectorized;
 
 namespace doris {
 
@@ -118,4 +121,44 @@ Status NullPredicate::evaluate(const Schema& schema,
     return Status::OK();
 }
 
+void NullPredicate::evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const {
+    uint16_t new_size = 0;
+    if (auto* nullable = check_and_get_column<ColumnNullable>(column)) {
+        auto& null_map = nullable->get_null_map_data();
+        for (uint16_t i = 0; i < *size; ++i) {
+            uint16_t idx = sel[i];
+            sel[new_size] = idx;
+            new_size += (null_map[idx] == _is_null);
+        }
+        *size = new_size;
+    } else {
+        if (_is_null) *size = 0;
+    }
+}
+
+void NullPredicate::evaluate_or(IColumn& column, uint16_t* sel, uint16_t size, bool* flags) const {
+    if (auto* nullable = check_and_get_column<ColumnNullable>(column)) {
+        auto& null_map = nullable->get_null_map_data();
+        for (uint16_t i = 0; i < size; ++i) {
+            if (flags[i]) continue;
+            uint16_t idx = sel[i];
+            flags[i] |= (null_map[idx] == _is_null);
+        }
+    } else {
+        if (!_is_null) memset(flags, true, size);
+    }
+}
+
+void NullPredicate::evaluate_and(IColumn& column, uint16_t* sel, uint16_t size, bool* flags) const {
+    if (auto* nullable = check_and_get_column<ColumnNullable>(column)) {
+        auto& null_map = nullable->get_null_map_data();
+        for (uint16_t i = 0; i < size; ++i) {
+            if (flags[i]) continue;
+            uint16_t idx = sel[i];
+            flags[i] &= (null_map[idx] == _is_null);
+        }
+    } else {
+        if (_is_null) memset(flags, false, size);
+    }
+}
 } //namespace doris
diff --git a/be/src/olap/null_predicate.h b/be/src/olap/null_predicate.h
index e867d58..681e60b 100644
--- a/be/src/olap/null_predicate.h
+++ b/be/src/olap/null_predicate.h
@@ -43,6 +43,14 @@ public:
     virtual Status evaluate(const Schema& schema, const vector<BitmapIndexIterator*>& iterators,
                             uint32_t num_rows, roaring::Roaring* roaring) const override;
 
+    void evaluate(vectorized::IColumn& column, uint16_t* sel, uint16_t* size) const override;
+
+    void evaluate_or(vectorized::IColumn& column, uint16_t* sel, uint16_t size,
+                     bool* flags) const override;
+
+    void evaluate_and(vectorized::IColumn& column, uint16_t* sel, uint16_t size,
+                      bool* flags) const override;
+
 private:
     bool _is_null; //true for null, false for not null
 };
diff --git a/be/src/olap/olap_define.h b/be/src/olap/olap_define.h
index c2d4b7f..a9ac731 100644
--- a/be/src/olap/olap_define.h
+++ b/be/src/olap/olap_define.h
@@ -384,7 +384,8 @@ enum OLAPStatus {
     OLAP_ERR_ROWSET_LOAD_FAILED = -3109,
     OLAP_ERR_ROWSET_READER_INIT = -3110,
     OLAP_ERR_ROWSET_READ_FAILED = -3111,
-    OLAP_ERR_ROWSET_INVALID_STATE_TRANSITION = -3112
+    OLAP_ERR_ROWSET_INVALID_STATE_TRANSITION = -3112,
+    OLAP_ERR_STRING_OVERFLOW_IN_VEC_ENGINE = -3113
 };
 
 enum ColumnFamilyIndex {
diff --git a/be/src/olap/reader.cpp b/be/src/olap/reader.cpp
index 763d1e7..13e50b8 100644
--- a/be/src/olap/reader.cpp
+++ b/be/src/olap/reader.cpp
@@ -41,6 +41,7 @@
 #include "runtime/string_value.hpp"
 #include "util/date_func.h"
 #include "util/mem_util.hpp"
+#include "vec/olap/vcollect_iterator.h"
 
 using std::nothrow;
 using std::set;
@@ -57,8 +58,8 @@ void TabletReader::ReaderParams::check_validation() const {
 std::string TabletReader::ReaderParams::to_string() const {
     std::stringstream ss;
     ss << "tablet=" << tablet->full_name() << " reader_type=" << reader_type
-       << " aggregation=" << aggregation << " version=" << version << " start_key_include=" << start_key_include
-       << " end_key_include=" << end_key_include;
+       << " aggregation=" << aggregation << " version=" << version
+       << " start_key_include=" << start_key_include << " end_key_include=" << end_key_include;
 
     for (const auto& key : start_key) {
         ss << " keys=" << key;
@@ -230,6 +231,7 @@ OLAPStatus TabletReader::_capture_rs_readers(const ReaderParams& read_params,
 OLAPStatus TabletReader::_init_params(const ReaderParams& read_params) {
     read_params.check_validation();
 
+    _direct_mode = read_params.direct_mode;
     _aggregation = read_params.aggregation;
     _need_agg_finalize = read_params.need_agg_finalize;
     _reader_type = read_params.reader_type;
@@ -699,7 +701,7 @@ ColumnPredicate* TabletReader::_parse_to_predicate(const TCondition& condition,
             break;
         }
         case OLAP_FIELD_TYPE_VARCHAR:
-        case OLAP_FIELD_TYPE_STRING:{
+        case OLAP_FIELD_TYPE_STRING: {
             phmap::flat_hash_set<StringValue> values;
             for (auto& cond_val : condition.condition_values) {
                 StringValue value;
@@ -806,7 +808,8 @@ void TabletReader::_init_load_bf_columns(const ReaderParams& read_params, Condit
         return;
     }
     FieldType type = _tablet->tablet_schema().column(max_equal_index).type();
-    if ((type != OLAP_FIELD_TYPE_VARCHAR && type != OLAP_FIELD_TYPE_STRING)|| max_equal_index + 1 > _tablet->num_short_key_columns()) {
+    if ((type != OLAP_FIELD_TYPE_VARCHAR && type != OLAP_FIELD_TYPE_STRING) ||
+        max_equal_index + 1 > _tablet->num_short_key_columns()) {
         load_bf_columns->erase(max_equal_index);
     }
 }
diff --git a/be/src/olap/reader.h b/be/src/olap/reader.h
index 0f20895..82cd7ff 100644
--- a/be/src/olap/reader.h
+++ b/be/src/olap/reader.h
@@ -49,6 +49,11 @@ class RowBlock;
 class CollectIterator;
 class RuntimeState;
 
+namespace vectorized {
+class VCollectIterator;
+class Block;
+} // namespace vectorized
+
 class TabletReader {
     struct KeysParam {
         std::string to_string() const;
@@ -64,6 +69,7 @@ public:
     struct ReaderParams {
         TabletSharedPtr tablet;
         ReaderType reader_type = READER_QUERY;
+        bool direct_mode = false;
         bool aggregation = false;
         bool need_agg_finalize = true;
         // 1. when read column data page:
@@ -88,6 +94,9 @@ public:
         RuntimeProfile* profile = nullptr;
         RuntimeState* runtime_state = nullptr;
 
+        // use only in vec exec engine
+        std::vector<uint32_t>* origin_return_columns = nullptr;
+
         void check_validation() const;
 
         std::string to_string() const;
@@ -105,7 +114,17 @@ public:
     // Return OLAP_SUCCESS and set `*eof` to true when no more rows can be read.
     // Return others when unexpected error happens.
     virtual OLAPStatus next_row_with_aggregation(RowCursor* row_cursor, MemPool* mem_pool,
-                                         ObjectPool* agg_pool, bool* eof) = 0;
+                                                 ObjectPool* agg_pool, bool* eof) = 0;
+
+    // Read next block with aggregation.
+    // Return OLAP_SUCCESS and set `*eof` to false when next block is read
+    // Return OLAP_SUCCESS and set `*eof` to true when no more rows can be read.
+    // Return others when unexpected error happens.
+    // TODO: Rethink here we still need mem_pool and agg_pool?
+    virtual OLAPStatus next_block_with_aggregation(vectorized::Block* block, MemPool* mem_pool,
+                                                   ObjectPool* agg_pool, bool* eof) {
+        return OLAP_ERR_READER_INITIALIZE_ERROR;
+    }
 
     uint64_t merged_rows() const { return _merged_rows; }
 
@@ -119,6 +138,7 @@ public:
 
 protected:
     friend class CollectIterator;
+    friend class vectorized::VCollectIterator;
     friend class DeleteHandler;
 
     OLAPStatus _init_params(const ReaderParams& read_params);
@@ -188,8 +208,8 @@ protected:
     ReaderType _reader_type = READER_QUERY;
     bool _next_delete_flag = false;
     bool _filter_delete = false;
-    bool _has_sequence_col = false;
     int32_t _sequence_col_idx = -1;
+    bool _direct_mode = false;
 
     CollectIterator _collect_iter;
     std::vector<uint32_t> _key_cids;
diff --git a/be/src/olap/row_block2.cpp b/be/src/olap/row_block2.cpp
index 20ed4ae..877f6a2 100644
--- a/be/src/olap/row_block2.cpp
+++ b/be/src/olap/row_block2.cpp
@@ -23,6 +23,11 @@
 #include "gutil/strings/substitute.h"
 #include "olap/row_cursor.h"
 #include "util/bitmap.h"
+#include "vec/columns/column_complex.h"
+#include "vec/columns/column_vector.h"
+#include "vec/core/block.h"
+#include "vec/core/types.h"
+#include "vec/runtime/vdatetime_value.h"
 
 using strings::Substitute;
 namespace doris {
@@ -90,6 +95,231 @@ Status RowBlockV2::convert_to_row_block(RowCursor* helper, RowBlock* dst) {
     return Status::OK();
 }
 
+Status RowBlockV2::_copy_data_to_column(int cid, doris::vectorized::MutableColumnPtr& origin_column) {
+    constexpr auto MAX_SIZE_OF_VEC_STRING = 1024l * 1024;
+
+    auto* column = origin_column.get();
+    bool nullable_mark_array[_selected_size];
+
+    bool column_nullable = origin_column->is_nullable();
+    bool origin_nullable = _schema.column(cid)->is_nullable();
+    if (column_nullable) {
+        auto nullable_column = assert_cast<vectorized::ColumnNullable*>(origin_column.get());
+        auto& null_map = nullable_column->get_null_map_data();
+        column = nullable_column->get_nested_column_ptr().get();
+
+        if (origin_nullable) {
+            for (uint16_t i = 0; i < _selected_size; ++i) {
+                uint16_t row_idx = _selection_vector[i];
+                null_map.push_back(_column_vector_batches[cid]->is_null_at(row_idx));
+                nullable_mark_array[i] = null_map.back();
+            }
+        } else {
+            null_map.resize_fill(null_map.size() + _selected_size, 0);
+            memset(nullable_mark_array, false, _selected_size * sizeof(bool));
+        }
+    } else {
+        memset(nullable_mark_array, false, _selected_size * sizeof(bool));
+    }
+
+    auto insert_data_directly = [this, &nullable_mark_array](int cid, auto& column) {
+        for (uint16_t j = 0; j < _selected_size; ++j) {
+            if (!nullable_mark_array[j]) {
+                uint16_t row_idx = _selection_vector[j];
+                column->insert_data(
+                        reinterpret_cast<const char*>(column_block(cid).cell_ptr(row_idx)), 0);
+            } else {
+                column->insert_default();
+            }
+        }
+    };
+
+    switch (_schema.column(cid)->type()) {
+    case OLAP_FIELD_TYPE_OBJECT: {
+        auto column_bitmap = assert_cast<vectorized::ColumnBitmap*>(column);
+        for (uint16_t j = 0; j < _selected_size; ++j) {
+            column_bitmap->insert_default();
+            if (!nullable_mark_array[j]) {
+                uint16_t row_idx = _selection_vector[j];
+                auto slice = reinterpret_cast<const Slice*>(column_block(cid).cell_ptr(row_idx));
+
+                BitmapValue* pvalue = &column_bitmap->get_element(column_bitmap->size() - 1);
+
+                if (slice->size != 0) {
+                    BitmapValue value;
+                    value.deserialize(slice->data);
+                    *pvalue = std::move(value);
+                } else {
+                    *pvalue = std::move(*reinterpret_cast<BitmapValue*>(slice->data));
+                }
+            }
+        }
+        break;
+    }
+    case OLAP_FIELD_TYPE_HLL:
+    case OLAP_FIELD_TYPE_MAP:
+    case OLAP_FIELD_TYPE_VARCHAR: {
+        auto column_string = assert_cast<vectorized::ColumnString*>(column);
+
+        for (uint16_t j = 0; j < _selected_size; ++j) {
+            if (!nullable_mark_array[j]) {
+                uint16_t row_idx = _selection_vector[j];
+                auto slice = reinterpret_cast<const Slice*>(column_block(cid).cell_ptr(row_idx));
+                column_string->insert_data(slice->data, slice->size);
+            } else {
+                column_string->insert_default();
+            }
+        }
+        break;
+    }
+    case OLAP_FIELD_TYPE_STRING: {
+        auto column_string = assert_cast<vectorized::ColumnString*>(column);
+
+        for (uint16_t j = 0; j < _selected_size; ++j) {
+            if (!nullable_mark_array[j]) {
+                uint16_t row_idx = _selection_vector[j];
+                auto slice = reinterpret_cast<const Slice*>(column_block(cid).cell_ptr(row_idx));
+                if (LIKELY(slice->size <= MAX_SIZE_OF_VEC_STRING)) {
+                    column_string->insert_data(slice->data, slice->size);
+                } else {
+                    return Status::NotSupported("Not support string len over than 1MB in vec engine.");
+                }
+            } else {
+                column_string->insert_default();
+            }
+        }
+        break;
+    }
+    case OLAP_FIELD_TYPE_CHAR: {
+        auto column_string = assert_cast<vectorized::ColumnString*>(column);
+
+        for (uint16_t j = 0; j < _selected_size; ++j) {
+            if (!nullable_mark_array[j]) {
+                uint16_t row_idx = _selection_vector[j];
+                auto slice = reinterpret_cast<const Slice*>(column_block(cid).cell_ptr(row_idx));
+                column_string->insert_data(slice->data, strnlen(slice->data, slice->size));
+            } else {
+                column_string->insert_default();
+            }
+        }
+        break;
+    }
+    case OLAP_FIELD_TYPE_DATE: {
+        auto column_int = assert_cast<vectorized::ColumnVector<vectorized::Int64>*>(column);
+
+        for (uint16_t j = 0; j < _selected_size; ++j) {
+            if (!nullable_mark_array[j]) {
+                uint16_t row_idx = _selection_vector[j];
+                auto ptr = reinterpret_cast<const char*>(column_block(cid).cell_ptr(row_idx));
+
+                uint64_t value = 0;
+                value = *(unsigned char*)(ptr + 2);
+                value <<= 8;
+                value |= *(unsigned char*)(ptr + 1);
+                value <<= 8;
+                value |= *(unsigned char*)(ptr);
+                vectorized::VecDateTimeValue date;
+                date.from_olap_date(value);
+                (column_int)->insert_data(reinterpret_cast<char*>(&date), 0);
+            } else
+                column_int->insert_default();
+        }
+        break;
+    }
+    case OLAP_FIELD_TYPE_DATETIME: {
+        auto column_int = assert_cast<vectorized::ColumnVector<vectorized::Int64>*>(column);
+
+        for (uint16_t j = 0; j < _selected_size; ++j) {
+            if (!nullable_mark_array[j]) {
+                uint16_t row_idx = _selection_vector[j];
+                auto ptr = reinterpret_cast<const char*>(column_block(cid).cell_ptr(row_idx));
+
+                uint64_t value = *reinterpret_cast<const uint64_t*>(ptr);
+                vectorized::VecDateTimeValue data(value);
+                (column_int)->insert_data(reinterpret_cast<char*>(&data), 0);
+            } else {
+                column_int->insert_default();
+            }
+        }
+        break;
+    }
+    case OLAP_FIELD_TYPE_DECIMAL: {
+        auto column_decimal =
+                assert_cast<vectorized::ColumnDecimal<vectorized::Decimal128>*>(column);
+
+        for (uint16_t j = 0; j < _selected_size; ++j) {
+            if (!nullable_mark_array[j]) {
+                uint16_t row_idx = _selection_vector[j];
+                auto ptr = reinterpret_cast<const char*>(column_block(cid).cell_ptr(row_idx));
+
+                int64_t int_value = *(int64_t*)(ptr);
+                int32_t frac_value = *(int32_t*)(ptr + sizeof(int64_t));
+                DecimalV2Value data(int_value, frac_value);
+                column_decimal->insert_data(reinterpret_cast<char*>(&data), 0);
+            } else {
+                column_decimal->insert_default();
+            }
+        }
+        break;
+    }
+    case OLAP_FIELD_TYPE_INT: {
+        auto column_int = assert_cast<vectorized::ColumnVector<vectorized::Int32>*>(column);
+        insert_data_directly(cid, column_int);
+        break;
+    }
+    case OLAP_FIELD_TYPE_BOOL: {
+        auto column_int = assert_cast<vectorized::ColumnVector<vectorized::UInt8>*>(column);
+        insert_data_directly(cid, column_int);
+        break;
+    }
+    case OLAP_FIELD_TYPE_TINYINT: {
+        auto column_int = assert_cast<vectorized::ColumnVector<vectorized::Int8>*>(column);
+        insert_data_directly(cid, column_int);
+        break;
+    }
+    case OLAP_FIELD_TYPE_SMALLINT: {
+        auto column_int = assert_cast<vectorized::ColumnVector<vectorized::Int16>*>(column);
+        insert_data_directly(cid, column_int);
+        break;
+    }
+    case OLAP_FIELD_TYPE_BIGINT: {
+        auto column_int = assert_cast<vectorized::ColumnVector<vectorized::Int64>*>(column);
+        insert_data_directly(cid, column_int);
+        break;
+    }
+    case OLAP_FIELD_TYPE_LARGEINT: {
+        auto column_int = assert_cast<vectorized::ColumnVector<vectorized::Int128>*>(column);
+        insert_data_directly(cid, column_int);
+        break;
+    }
+    case OLAP_FIELD_TYPE_FLOAT: {
+        auto column_float = assert_cast<vectorized::ColumnVector<vectorized::Float32>*>(column);
+        insert_data_directly(cid, column_float);
+        break;
+    }
+    case OLAP_FIELD_TYPE_DOUBLE: {
+        auto column_float = assert_cast<vectorized::ColumnVector<vectorized::Float64>*>(column);
+        insert_data_directly(cid, column_float);
+        break;
+    }
+    default: {
+        DCHECK(false) << "Invalid type in RowBlockV2:" << _schema.column(cid)->type();
+    }
+    }
+
+    return Status::OK();
+}
+
+Status RowBlockV2::convert_to_vec_block(vectorized::Block* block) {
+    for (int i = 0; i < _schema.column_ids().size(); ++i) {
+        auto cid = _schema.column_ids()[i];
+        auto column = (*std::move(block->get_by_position(i).column)).assume_mutable();
+        RETURN_IF_ERROR(_copy_data_to_column(cid, column));
+    }
+    _pool->clear();
+    return Status::OK();
+}
+
 std::string RowBlockRow::debug_string() const {
     std::stringstream ss;
     ss << "[";
diff --git a/be/src/olap/row_block2.h b/be/src/olap/row_block2.h
index ece8d72..b98ab95 100644
--- a/be/src/olap/row_block2.h
+++ b/be/src/olap/row_block2.h
@@ -73,6 +73,9 @@ public:
     // convert RowBlockV2 to RowBlock
     Status convert_to_row_block(RowCursor* helper, RowBlock* dst);
 
+    // convert RowBlockV2 to vectorized::Block
+    Status convert_to_vec_block(vectorized::Block* block);
+
     // low-level API to access memory for each column block(including data array and nullmap).
     // `cid` must be one of `schema()->column_ids()`.
     ColumnBlock column_block(ColumnId cid) const {
@@ -106,6 +109,8 @@ public:
     std::string debug_string();
 
 private:
+    Status _copy_data_to_column(int cid, vectorized::MutableColumnPtr& mutable_column_ptr);
+
     Schema _schema;
     size_t _capacity;
     // _column_vector_batches[cid] == null if cid is not in `_schema`.
diff --git a/be/src/olap/rowset/alpha_rowset_reader.h b/be/src/olap/rowset/alpha_rowset_reader.h
index 959a90b..fd90f37 100644
--- a/be/src/olap/rowset/alpha_rowset_reader.h
+++ b/be/src/olap/rowset/alpha_rowset_reader.h
@@ -65,6 +65,10 @@ public:
     // It's ok, because we only get ref here, the block's owner is this reader.
     OLAPStatus next_block(RowBlock** block) override;
 
+    OLAPStatus next_block(vectorized::Block *block) override {
+        return OLAP_ERR_DATA_EOF;
+    }
+
     bool delete_flag() override;
 
     Version version() override;
diff --git a/be/src/olap/rowset/beta_rowset_reader.cpp b/be/src/olap/rowset/beta_rowset_reader.cpp
index ada5157..4d35f2f 100644
--- a/be/src/olap/rowset/beta_rowset_reader.cpp
+++ b/be/src/olap/rowset/beta_rowset_reader.cpp
@@ -27,6 +27,8 @@
 #include "olap/rowset/segment_v2/segment_iterator.h"
 #include "olap/schema.h"
 
+#include "vec/core/block.h"
+
 namespace doris {
 
 BetaRowsetReader::BetaRowsetReader(BetaRowsetSharedPtr rowset,
@@ -107,7 +109,8 @@ OLAPStatus BetaRowsetReader::init(RowsetReaderContext* read_context) {
         }
         seg_iterators.push_back(std::move(iter));
     }
-    std::list<RowwiseIterator*> iterators;
+
+    std::vector<RowwiseIterator*> iterators;
     for (auto& owned_it : seg_iterators) {
         // transfer ownership of segment iterator to `_iterator`
         iterators.push_back(owned_it.release());
@@ -172,4 +175,45 @@ OLAPStatus BetaRowsetReader::next_block(RowBlock** block) {
     return OLAP_SUCCESS;
 }
 
+OLAPStatus BetaRowsetReader::next_block(vectorized::Block* block) {
+    SCOPED_RAW_TIMER(&_stats->block_fetch_ns);
+    bool is_first = true;
+
+    do {
+        // read next input block
+        {
+            _input_block->clear();
+            {
+                auto s = _iterator->next_batch(_input_block.get());
+                if (!s.ok()) {
+                    if (s.is_end_of_file()) {
+                        if (is_first) {
+                            return OLAP_ERR_DATA_EOF;
+                        } else {
+                            break;
+                        }
+                    } else {
+                        LOG(WARNING) << "failed to read next block: " << s.to_string();
+                        return OLAP_ERR_ROWSET_READ_FAILED;
+                    }
+                } else if (_input_block->selected_size() == 0) {
+                    continue;
+                }
+            }
+        }
+
+        {
+            SCOPED_RAW_TIMER(&_stats->block_convert_ns);
+            auto s = _input_block->convert_to_vec_block(block);
+            if (UNLIKELY(!s.ok())) {
+                LOG(WARNING) << "failed to read next block: " << s.to_string();
+                return OLAP_ERR_STRING_OVERFLOW_IN_VEC_ENGINE;
+            }
+        }
+        is_first = false;
+    } while (block->rows() < _context->runtime_state->batch_size()); // here we should keep block.rows() < batch_size
+
+    return OLAP_SUCCESS;
+}
+
 } // namespace doris
diff --git a/be/src/olap/rowset/beta_rowset_reader.h b/be/src/olap/rowset/beta_rowset_reader.h
index 34e7d9c..6074308 100644
--- a/be/src/olap/rowset/beta_rowset_reader.h
+++ b/be/src/olap/rowset/beta_rowset_reader.h
@@ -40,6 +40,7 @@ public:
     // If parent_tracker is not null, the block we get from next_block() will have the parent_tracker.
     // It's ok, because we only get ref here, the block's owner is this reader.
     OLAPStatus next_block(RowBlock** block) override;
+    OLAPStatus next_block(vectorized::Block* block) override;
 
     bool delete_flag() override { return _rowset->delete_flag(); }
 
diff --git a/be/src/olap/rowset/rowset_reader.h b/be/src/olap/rowset/rowset_reader.h
index b9e46d1..53af387 100644
--- a/be/src/olap/rowset/rowset_reader.h
+++ b/be/src/olap/rowset/rowset_reader.h
@@ -23,9 +23,14 @@
 
 #include "olap/rowset/rowset.h"
 #include "olap/rowset/rowset_reader_context.h"
+#include "vec/core/block.h"
 
 namespace doris {
 
+namespace vectorized {
+class Block;
+}
+
 class RowBlock;
 class RowsetReader;
 using RowsetReaderSharedPtr = std::shared_ptr<RowsetReader>;
@@ -33,6 +38,7 @@ using RowsetReaderSharedPtr = std::shared_ptr<RowsetReader>;
 class RowsetReader {
 public:
     enum RowsetReaderType { ALPHA, BETA };
+
     virtual ~RowsetReader() {}
 
     // reader init
@@ -45,6 +51,8 @@ public:
     //      Others when error happens.
     virtual OLAPStatus next_block(RowBlock** block) = 0;
 
+    virtual OLAPStatus next_block(vectorized::Block* block) = 0;
+
     virtual bool delete_flag() = 0;
 
     virtual Version version() = 0;
diff --git a/be/src/olap/rowset/segment_v2/binary_dict_page.cpp b/be/src/olap/rowset/segment_v2/binary_dict_page.cpp
index 6fae7eb..edd64db 100644
--- a/be/src/olap/rowset/segment_v2/binary_dict_page.cpp
+++ b/be/src/olap/rowset/segment_v2/binary_dict_page.cpp
@@ -19,9 +19,12 @@
 
 #include "common/logging.h"
 #include "gutil/strings/substitute.h" // for Substitute
-#include "olap/rowset/segment_v2/bitshuffle_page.h"
 #include "runtime/mem_pool.h"
 #include "util/slice.h" // for Slice
+#include "vec/columns/column_vector.h"
+#include "vec/columns/column_string.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/columns/predicate_column.h"
 
 namespace doris {
 namespace segment_v2 {
@@ -220,6 +223,8 @@ Status BinaryDictPageDecoder::init() {
     return Status::OK();
 }
 
+BinaryDictPageDecoder::~BinaryDictPageDecoder() {}
+
 Status BinaryDictPageDecoder::seek_to_position_in_page(size_t pos) {
     return _data_page_decoder->seek_to_position_in_page(pos);
 }
@@ -230,8 +235,64 @@ bool BinaryDictPageDecoder::is_dict_encoding() const {
 
 void BinaryDictPageDecoder::set_dict_decoder(PageDecoder* dict_decoder) {
     _dict_decoder = (BinaryPlainPageDecoder*)dict_decoder;
+    _bit_shuffle_ptr = reinterpret_cast<BitShufflePageDecoder<OLAP_FIELD_TYPE_INT>*>(_data_page_decoder.get());
 };
 
+Status BinaryDictPageDecoder::next_batch(size_t* n, vectorized::MutableColumnPtr &dst) {
+    if (_encoding_type == PLAIN_ENCODING) {
+        return _data_page_decoder->next_batch(n, dst);
+    }
+    // dictionary encoding
+    DCHECK(_parsed);
+    DCHECK(_dict_decoder != nullptr) << "dict decoder pointer is nullptr";
+ 
+    if (PREDICT_FALSE(*n == 0 || _bit_shuffle_ptr->_cur_index >= _bit_shuffle_ptr->_num_elements)) {
+        *n = 0;
+        return Status::OK();
+    }
+ 
+    size_t max_fetch = std::min(*n, static_cast<size_t>(_bit_shuffle_ptr->_num_elements - _bit_shuffle_ptr->_cur_index));
+    *n = max_fetch;
+ 
+    const int32_t* data_array = reinterpret_cast<const int32_t*>(_bit_shuffle_ptr->_chunk.data);
+    size_t start_index = _bit_shuffle_ptr->_cur_index;
+
+    auto* dst_col_ptr = dst.get();
+    if (dst->is_nullable()) {
+        auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+        dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+        
+        // fill null bitmap here, not null;
+        // todo(wb) using SIMD speed up here
+        for (int i = 0; i < max_fetch; i++) {
+            nullable_column->get_null_map_data().push_back(0);
+        }
+    }
+
+    if (dst_col_ptr->is_predicate_column()) {
+        // cast columnptr to columnstringvalue just for avoid virtual function call overhead
+        auto* string_value_column_ptr = reinterpret_cast<vectorized::ColumnStringValue*>(dst_col_ptr);
+        for (int i = 0; i < max_fetch; i++, start_index++) {
+            int32_t codeword = data_array[start_index];
+            uint32_t start_offset = _start_offset_array[codeword];
+            uint32_t str_len = _len_array[codeword];
+            string_value_column_ptr->insert_data(&_dict_decoder->_data[start_offset], str_len);
+        }
+    } else {
+             // todo(wb) research whether using batch memcpy to insert columnString can has better performance when data set is big
+        for (int i = 0; i < max_fetch; i++, start_index++) {
+            int32_t codeword = data_array[start_index];
+            const uint32_t start_offset = _start_offset_array[codeword];
+            const uint32_t str_len = _len_array[codeword];
+            dst_col_ptr->insert_data(&_dict_decoder->_data[start_offset], str_len);
+        }
+    }
+    _bit_shuffle_ptr->_cur_index += max_fetch;
+ 
+    return Status::OK();
+ 
+}
+
 Status BinaryDictPageDecoder::next_batch(size_t* n, ColumnBlockView* dst) {
     if (_encoding_type == PLAIN_ENCODING) {
         return _data_page_decoder->next_batch(n, dst);
diff --git a/be/src/olap/rowset/segment_v2/binary_dict_page.h b/be/src/olap/rowset/segment_v2/binary_dict_page.h
index 9290466..25a70b9 100644
--- a/be/src/olap/rowset/segment_v2/binary_dict_page.h
+++ b/be/src/olap/rowset/segment_v2/binary_dict_page.h
@@ -33,6 +33,7 @@
 #include "olap/types.h"
 #include "runtime/mem_pool.h"
 #include "runtime/mem_tracker.h"
+#include "olap/rowset/segment_v2/bitshuffle_page.h"
 
 namespace doris {
 namespace segment_v2 {
@@ -106,6 +107,8 @@ public:
 
     Status next_batch(size_t* n, ColumnBlockView* dst) override;
 
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) override;
+
     size_t count() const override { return _data_page_decoder->count(); }
 
     size_t current_index() const override { return _data_page_decoder->current_index(); }
@@ -114,15 +117,21 @@ public:
 
     void set_dict_decoder(PageDecoder* dict_decoder);
 
+    ~BinaryDictPageDecoder();
+
 private:
     Slice _data;
     PageDecoderOptions _options;
     std::unique_ptr<PageDecoder> _data_page_decoder;
     const BinaryPlainPageDecoder* _dict_decoder = nullptr;
+    BitShufflePageDecoder<OLAP_FIELD_TYPE_INT>* _bit_shuffle_ptr = nullptr;
     bool _parsed;
     EncodingTypePB _encoding_type;
     // use as data buf.
     std::unique_ptr<ColumnVectorBatch> _batch;
+
+    uint32_t* _start_offset_array = nullptr;
+    uint32_t* _len_array = nullptr;
 };
 
 } // namespace segment_v2
diff --git a/be/src/olap/rowset/segment_v2/binary_plain_page.h b/be/src/olap/rowset/segment_v2/binary_plain_page.h
index 0747df2..3c55d2b 100644
--- a/be/src/olap/rowset/segment_v2/binary_plain_page.h
+++ b/be/src/olap/rowset/segment_v2/binary_plain_page.h
@@ -38,6 +38,8 @@
 #include "runtime/mem_pool.h"
 #include "util/coding.h"
 #include "util/faststring.h"
+#include "vec/columns/column_complex.h"
+#include "vec/columns/column_nullable.h"
 
 namespace doris {
 namespace segment_v2 {
@@ -227,6 +229,61 @@ public:
         return Status::OK();
     }
 
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) override {
+        DCHECK(_parsed);
+        if (PREDICT_FALSE(*n == 0 || _cur_idx >= _num_elems)) {
+            *n = 0;
+            return Status::OK();
+        }
+        const size_t max_fetch = std::min(*n, static_cast<size_t>(_num_elems - _cur_idx));
+
+        auto* dst_col_ptr = dst.get();
+        if (dst->is_nullable()) {
+            auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+            dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+            // fill null bitmap here, not null;
+            for (int i = 0; i < max_fetch; i++) {
+                nullable_column->get_null_map_data().push_back(0);
+            }
+        }
+
+        if (dst_col_ptr->is_bitmap()) {
+            auto& bitmap_column = reinterpret_cast<vectorized::ColumnBitmap&>(*dst_col_ptr);
+            for (size_t i = 0; i < max_fetch; i++, _cur_idx++) {
+                const uint32_t start_offset  = offset(_cur_idx);
+                uint32_t len = offset(_cur_idx + 1) - start_offset;
+                
+                bitmap_column.insert_default();
+                BitmapValue* pvalue = &bitmap_column.get_element(bitmap_column.size() - 1);
+                if (len != 0) {
+                    BitmapValue value;
+                    value.deserialize(&_data[start_offset]);
+                    *pvalue = std::move(value);
+                } else {
+                    *pvalue = std::move(*reinterpret_cast<BitmapValue*>(const_cast<char*>(&_data[start_offset])));   
+                }
+            }
+        } else if (dst_col_ptr->is_predicate_column()) {
+            // todo(wb) padding sv here for better comparison performance
+            for (size_t i = 0; i < max_fetch; i++, _cur_idx++) {
+                const uint32_t start_offset  = offset(_cur_idx);
+                uint32_t len = offset(_cur_idx + 1) - start_offset;
+                StringValue sv(const_cast<char*>(&_data[start_offset]), len);
+                dst_col_ptr->insert_data(reinterpret_cast<char*>(&sv), 0);
+            }
+        } else {
+            for (size_t i = 0; i < max_fetch; i++, _cur_idx++) {
+                // todo(wb) need more test case and then improve here
+                const uint32_t start_offset  = offset(_cur_idx);
+                uint32_t len = offset(_cur_idx + 1) - start_offset;
+                dst_col_ptr->insert_data(&_data[start_offset], len);
+            }
+        }
+ 
+        *n = max_fetch;
+        return Status::OK();
+    };
+
     size_t count() const override {
         DCHECK(_parsed);
         return _num_elems;
@@ -263,6 +320,8 @@ private:
 
     // Index of the currently seeked element in the page.
     uint32_t _cur_idx;
+    friend class BinaryDictPageDecoder;
+    friend class FileColumnIterator;
 };
 
 } // namespace segment_v2
diff --git a/be/src/olap/rowset/segment_v2/binary_prefix_page.h b/be/src/olap/rowset/segment_v2/binary_prefix_page.h
index 7e51b82..7d7bcc9 100644
--- a/be/src/olap/rowset/segment_v2/binary_prefix_page.h
+++ b/be/src/olap/rowset/segment_v2/binary_prefix_page.h
@@ -113,6 +113,10 @@ public:
 
     Status next_batch(size_t* n, ColumnBlockView* dst) override;
 
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) override {
+        return Status::NotSupported("binary prefix page not implement vec op now");
+    };
+
     size_t count() const override {
         DCHECK(_parsed);
         return _num_values;
diff --git a/be/src/olap/rowset/segment_v2/bitshuffle_page.h b/be/src/olap/rowset/segment_v2/bitshuffle_page.h
index cd54b6b..83eebae 100644
--- a/be/src/olap/rowset/segment_v2/bitshuffle_page.h
+++ b/be/src/olap/rowset/segment_v2/bitshuffle_page.h
@@ -37,6 +37,8 @@
 #include "util/coding.h"
 #include "util/faststring.h"
 #include "util/slice.h"
+#include "vec/runtime/vdatetime_value.h"
+#include "vec/columns/column_nullable.h"
 
 namespace doris {
 namespace segment_v2 {
@@ -348,6 +350,71 @@ public:
         return Status::OK();
     }
 
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) override {
+        DCHECK(_parsed);
+        if (PREDICT_FALSE(*n == 0 || _cur_index >= _num_elements)) {
+            *n = 0;
+            return Status::OK();
+        }
+ 
+        size_t max_fetch = std::min(*n, static_cast<size_t>(_num_elements - _cur_index));
+ 
+        int begin = _cur_index;
+        int end = _cur_index + max_fetch;
+
+        auto* dst_col_ptr = dst.get();
+        if (dst->is_nullable()) {
+            auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+            dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+
+            // fill null bitmap here, not null;
+            for (int j = begin; j < end; j++) {
+                nullable_column->get_null_map_data().push_back(0);
+            }
+        }
+
+        // todo(wb) Try to eliminate type judgment in pagedecoder
+        if (dst_col_ptr->is_column_decimal()) { // decimal non-predicate column
+            for (; begin < end; begin++) {
+                const char* cur_ptr = (const char*)&_chunk.data[begin * SIZE_OF_TYPE];
+                int64_t int_value = *(int64_t*)(cur_ptr);
+                int32_t frac_value = *(int32_t*)(cur_ptr + sizeof(int64_t));
+                DecimalV2Value data(int_value, frac_value);
+                dst_col_ptr->insert_data(reinterpret_cast<char*>(&data), 0);
+            }
+        } else if (dst_col_ptr->is_date_type()) {
+            for (; begin < end; begin++) {
+                const char* cur_ptr = (const char*)&_chunk.data[begin * SIZE_OF_TYPE];
+                uint64_t value = 0;
+                value = *(unsigned char*)(cur_ptr + 2);
+                value <<= 8;
+                value |= *(unsigned char*)(cur_ptr + 1);
+                value <<= 8;
+                value |= *(unsigned char*)(cur_ptr);
+                vectorized::VecDateTimeValue date;
+                date.from_olap_date(value);
+                dst_col_ptr->insert_data(reinterpret_cast<char*>(&date), 0);
+            }
+        } else if (dst_col_ptr->is_datetime_type()) {
+            for (; begin < end; begin++) {
+                const char* cur_ptr = (const char*)&_chunk.data[begin * SIZE_OF_TYPE];
+                uint64_t value = *reinterpret_cast<const uint64_t*>(cur_ptr);
+                vectorized::VecDateTimeValue date(value);
+                dst_col_ptr->insert_data(reinterpret_cast<char*>(&date), 0);
+            }
+        } else {
+            // todo(wb) batch insert here
+            for (; begin < end; begin++) {
+                dst_col_ptr->insert_data((const char*)&_chunk.data[begin * SIZE_OF_TYPE], 0);
+            }
+        }
+
+        *n = max_fetch;
+        _cur_index += max_fetch;
+ 
+        return Status::OK();
+    };
+
     Status peek_next_batch(size_t* n, ColumnBlockView* dst) override {
         return next_batch<false>(n, dst);
     }
@@ -393,6 +460,7 @@ private:
     int _size_of_element;
     size_t _cur_index;
     Chunk _chunk;
+    friend class BinaryDictPageDecoder;
 };
 
 } // namespace segment_v2
diff --git a/be/src/olap/rowset/segment_v2/column_reader.cpp b/be/src/olap/rowset/segment_v2/column_reader.cpp
index 3bbbeab..c08b328 100644
--- a/be/src/olap/rowset/segment_v2/column_reader.cpp
+++ b/be/src/olap/rowset/segment_v2/column_reader.cpp
@@ -30,6 +30,8 @@
 #include "util/block_compression.h"
 #include "util/coding.h"       // for get_varint32
 #include "util/rle_encoding.h" // for RleDecoder
+#include "vec/core/types.h"
+#include "vec/runtime/vdatetime_value.h" //for VecDateTime
 
 namespace doris {
 namespace segment_v2 {
@@ -578,6 +580,57 @@ Status FileColumnIterator::next_batch(size_t* n, ColumnBlockView* dst, bool* has
     return Status::OK();
 }
 
+Status FileColumnIterator::next_batch(size_t* n, vectorized::MutableColumnPtr &dst, bool* has_null) {
+    size_t curr_size = dst->byte_size();
+    size_t remaining = *n;
+    *has_null = false;
+    while (remaining > 0) {
+        if (!_page->has_remaining()) {
+            bool eos = false;
+            RETURN_IF_ERROR(_load_next_page(&eos));
+            if (eos) {
+                break;
+            }
+        }
+
+        // number of rows to be read from this page
+        size_t nrows_in_page = std::min(remaining, _page->remaining());
+        size_t nrows_to_read = nrows_in_page;
+        if (_page->has_null) {
+            while (nrows_to_read > 0) {
+                bool is_null = false;
+                size_t this_run = _page->null_decoder.GetNextRun(&is_null, nrows_to_read);
+                // we use num_rows only for CHECK
+                size_t num_rows = this_run;
+                if (!is_null) {
+                    RETURN_IF_ERROR(_page->data_decoder->next_batch(&num_rows, dst));
+                    DCHECK_EQ(this_run, num_rows);
+                } else {
+                    *has_null = true;
+                    // todo(wb) add a DCHECK here to check whether type is column nullable
+                    for (size_t x = 0; x < this_run; x++) {
+                        dst->insert_data(nullptr, 0); // todo(wb) vectorized here
+                    }
+                }
+
+                nrows_to_read -= this_run;
+                _page->offset_in_page += this_run;
+                _current_ordinal += this_run;
+            }
+        } else {
+            RETURN_IF_ERROR(_page->data_decoder->next_batch(&nrows_to_read, dst));
+            DCHECK_EQ(nrows_to_read, nrows_in_page);
+
+            _page->offset_in_page += nrows_to_read;
+            _current_ordinal += nrows_to_read;
+        }
+        remaining -= nrows_in_page;
+    }
+    *n -= remaining;
+    _opts.stats->bytes_read += (dst->byte_size() - curr_size) + BitmapSize(*n);
+    return Status::OK();
+}
+
 Status FileColumnIterator::_load_next_page(bool* eos) {
     _page_iter.next();
     if (!_page_iter.valid()) {
@@ -715,5 +768,55 @@ Status DefaultValueColumnIterator::next_batch(size_t* n, ColumnBlockView* dst, b
     return Status::OK();
 }
 
+void DefaultValueColumnIterator::insert_default_data(vectorized::MutableColumnPtr &dst, size_t n) {
+    vectorized::Int128 int128;
+    char* data_ptr = (char*)&int128;
+    size_t data_len = sizeof(int128);
+
+    auto type = _type_info->type();
+    if (type == OLAP_FIELD_TYPE_DATE) {
+        assert(_type_size == sizeof(FieldTypeTraits<OLAP_FIELD_TYPE_DATE>::CppType)); //uint24_t
+        std::string str = FieldTypeTraits<OLAP_FIELD_TYPE_DATE>::to_string(_mem_value);
+
+        vectorized::VecDateTimeValue value;
+        value.from_date_str(str.c_str(), str.length());
+        value.cast_to_date();
+        //TODO: here is int128 = int64
+        int128 = binary_cast<vectorized::VecDateTimeValue, vectorized::Int64>(value);
+    } else if (type == OLAP_FIELD_TYPE_DATETIME) {
+        assert(_type_size == sizeof(FieldTypeTraits<OLAP_FIELD_TYPE_DATETIME>::CppType)); //int64_t
+        std::string str = FieldTypeTraits<OLAP_FIELD_TYPE_DATETIME>::to_string(_mem_value);
+
+        vectorized::VecDateTimeValue value;
+        value.from_date_str(str.c_str(), str.length());
+        value.to_datetime();
+
+        int128 = binary_cast<vectorized::VecDateTimeValue, vectorized::Int64>(value);
+    } else if (type == OLAP_FIELD_TYPE_DECIMAL) {
+        assert(_type_size == sizeof(FieldTypeTraits<OLAP_FIELD_TYPE_DECIMAL>::CppType)); //decimal12_t
+        decimal12_t* d = (decimal12_t*)_mem_value;
+        int128 = DecimalV2Value(d->integer, d->fraction).value();
+    } else {
+        data_ptr = (char*)_mem_value;
+        data_len = _type_size;
+    }
+
+    for (size_t i = 0; i < n; ++i) {
+        dst->insert_data(data_ptr, data_len);
+    }
+}
+
+Status DefaultValueColumnIterator::next_batch(size_t* n, vectorized::MutableColumnPtr &dst, bool* has_null) {
+    if (_is_default_value_null) {
+        *has_null = true;
+        dst->insert_many_defaults(*n);
+    } else {
+        *has_null = false;
+        insert_default_data(dst, *n);
+    }
+
+    return Status::OK();
+}
+
 } // namespace segment_v2
 } // namespace doris
diff --git a/be/src/olap/rowset/segment_v2/column_reader.h b/be/src/olap/rowset/segment_v2/column_reader.h
index 0b3588c..98afe44 100644
--- a/be/src/olap/rowset/segment_v2/column_reader.h
+++ b/be/src/olap/rowset/segment_v2/column_reader.h
@@ -215,11 +215,20 @@ public:
         return next_batch(n, dst, &has_null);
     }
 
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) {
+        bool has_null;
+        return next_batch(n, dst, &has_null);
+    }
+
     // After one seek, we can call this function many times to read data
     // into ColumnBlockView. when read string type data, memory will allocated
     // from MemPool
     virtual Status next_batch(size_t* n, ColumnBlockView* dst, bool* has_null) = 0;
 
+    virtual Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst, bool* has_null) {
+        return Status::NotSupported("not implement");
+    }
+
     virtual ordinal_t get_current_ordinal() const = 0;
 
     virtual Status get_row_ranges_by_zone_map(CondColumn* cond_column, CondColumn* delete_condition,
@@ -268,6 +277,8 @@ public:
 
     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;
+
     ordinal_t get_current_ordinal() const override { return _current_ordinal; }
 
     // get row ranges by zone map
@@ -401,11 +412,20 @@ public:
         return Status::OK();
     }
 
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) {
+        bool has_null;
+        return next_batch(n, dst, &has_null);
+    }
+
     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;
+
     ordinal_t get_current_ordinal() const override { return _current_rowid; }
 
 private:
+    void insert_default_data(vectorized::MutableColumnPtr &dst, size_t n);
+
     bool _has_default_value;
     std::string _default_value;
     bool _is_nullable;
diff --git a/be/src/olap/rowset/segment_v2/empty_segment_iterator.cpp b/be/src/olap/rowset/segment_v2/empty_segment_iterator.cpp
index 61c0fab..f367c2d 100644
--- a/be/src/olap/rowset/segment_v2/empty_segment_iterator.cpp
+++ b/be/src/olap/rowset/segment_v2/empty_segment_iterator.cpp
@@ -30,5 +30,9 @@ Status EmptySegmentIterator::next_batch(RowBlockV2* block) {
     return Status::EndOfFile("no more data in segment");
 }
 
+Status EmptySegmentIterator::next_batch(vectorized::Block* block) {
+    return Status::EndOfFile("no more data in segment");
+}
+
 } // namespace segment_v2
-} // namespace doris
\ No newline at end of file
+} // namespace doris
diff --git a/be/src/olap/rowset/segment_v2/empty_segment_iterator.h b/be/src/olap/rowset/segment_v2/empty_segment_iterator.h
index cb6c48c..3e1a4f9 100644
--- a/be/src/olap/rowset/segment_v2/empty_segment_iterator.h
+++ b/be/src/olap/rowset/segment_v2/empty_segment_iterator.h
@@ -32,10 +32,11 @@ public:
     Status init(const StorageReadOptions& opts) override { return Status::OK(); }
     const Schema& schema() const override { return _schema; }
     Status next_batch(RowBlockV2* row_block) override;
+    Status next_batch(vectorized::Block* block) override;
 
 private:
     Schema _schema;
 };
 
 } // namespace segment_v2
-} // namespace doris
\ No newline at end of file
+} // namespace doris
diff --git a/be/src/olap/rowset/segment_v2/frame_of_reference_page.h b/be/src/olap/rowset/segment_v2/frame_of_reference_page.h
index 5d0c0b1..df8fe06 100644
--- a/be/src/olap/rowset/segment_v2/frame_of_reference_page.h
+++ b/be/src/olap/rowset/segment_v2/frame_of_reference_page.h
@@ -161,6 +161,10 @@ public:
         return Status::OK();
     }
 
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) override {
+        return Status::NotSupported("frame page not implement vec op now");
+    };
+
     Status peek_next_batch(size_t* n, ColumnBlockView* dst) override {
         return next_batch<false>(n, dst);
     }
diff --git a/be/src/olap/rowset/segment_v2/page_decoder.h b/be/src/olap/rowset/segment_v2/page_decoder.h
index feed37f..ab5b482 100644
--- a/be/src/olap/rowset/segment_v2/page_decoder.h
+++ b/be/src/olap/rowset/segment_v2/page_decoder.h
@@ -19,6 +19,7 @@
 
 #include "common/status.h"     // for Status
 #include "olap/column_block.h" // for ColumnBlockView
+#include "vec/columns/column.h"
 
 namespace doris {
 namespace segment_v2 {
@@ -81,6 +82,10 @@ public:
     // allocated in the column_vector_view's mem_pool.
     virtual Status next_batch(size_t* n, ColumnBlockView* dst) = 0;
 
+    virtual Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) {
+        return Status::NotSupported("not implement vec op now");
+    }
+
     // Same as `next_batch` except for not moving forward the cursor.
     // When read array's ordinals in `ArrayFileColumnIterator`, we want to read one extra ordinal
     // but do not want to move forward the cursor.
diff --git a/be/src/olap/rowset/segment_v2/plain_page.h b/be/src/olap/rowset/segment_v2/plain_page.h
index 555c9af..09e4280 100644
--- a/be/src/olap/rowset/segment_v2/plain_page.h
+++ b/be/src/olap/rowset/segment_v2/plain_page.h
@@ -186,6 +186,10 @@ public:
 
     Status next_batch(size_t* n, ColumnBlockView* dst) override { return next_batch<true>(n, dst); }
 
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) override {
+        return Status::NotSupported("plain page not implement vec op now");
+    };
+
     template <bool forward_index>
     inline Status next_batch(size_t* n, ColumnBlockView* dst) {
         DCHECK(_parsed);
diff --git a/be/src/olap/rowset/segment_v2/rle_page.h b/be/src/olap/rowset/segment_v2/rle_page.h
index ed20aaf..52a9613 100644
--- a/be/src/olap/rowset/segment_v2/rle_page.h
+++ b/be/src/olap/rowset/segment_v2/rle_page.h
@@ -230,6 +230,29 @@ public:
         return Status::OK();
     }
 
+    Status next_batch(size_t* n, vectorized::MutableColumnPtr &dst) override {
+        DCHECK(_parsed);
+        if (PREDICT_FALSE(*n == 0 || _cur_index >= _num_elements)) {
+            *n = 0;
+            return Status::OK();
+        }
+
+        size_t to_fetch = std::min(*n, static_cast<size_t>(_num_elements - _cur_index));
+        size_t remaining = to_fetch;
+        bool result = false;
+        CppType value;
+        while (remaining > 0) {
+            result = _rle_decoder.Get(&value);
+            DCHECK(result);
+            dst->insert_data((char*)(&value), SIZE_OF_TYPE);
+            remaining--;
+        }
+
+        _cur_index += to_fetch;
+        *n = to_fetch;
+        return Status::OK();
+    };
+
     size_t count() const override { return _num_elements; }
 
     size_t current_index() const override { return _cur_index; }
diff --git a/be/src/olap/rowset/segment_v2/segment_iterator.cpp b/be/src/olap/rowset/segment_v2/segment_iterator.cpp
index cb7e0d5..86a89ac 100644
--- a/be/src/olap/rowset/segment_v2/segment_iterator.cpp
+++ b/be/src/olap/rowset/segment_v2/segment_iterator.cpp
@@ -30,6 +30,7 @@
 #include "olap/rowset/segment_v2/segment.h"
 #include "olap/short_key_index.h"
 #include "util/doris_metrics.h"
+#include "olap/in_list_predicate.h"
 
 using strings::Substitute;
 
@@ -120,7 +121,7 @@ Status SegmentIterator::init(const StorageReadOptions& opts) {
     return Status::OK();
 }
 
-Status SegmentIterator::_init() {
+Status SegmentIterator::_init(bool is_vec) {
     DorisMetrics::instance()->segment_read_total->increment(1);
     // get file handle from file descriptor of segment
     fs::BlockManager* block_mgr = fs::fs_util::block_manager(_segment->_path_desc.storage_medium);
@@ -133,7 +134,11 @@ Status SegmentIterator::_init() {
         RETURN_IF_ERROR(_get_row_ranges_by_keys());
     }
     RETURN_IF_ERROR(_get_row_ranges_by_column_conditions());
-    _init_lazy_materialization();
+    if (is_vec) {
+        _vec_init_lazy_materialization();
+    } else {
+        _init_lazy_materialization();
+    }
     _range_iter.reset(new BitmapRangeIterator(_row_bitmap));
     return Status::OK();
 }
@@ -581,5 +586,359 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
     return Status::OK();
 }
 
+/* ---------------------- for vecterization implementation  ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+    _is_pred_column.resize(_schema.columns().size(), false);
+
+    std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+    _is_all_column_basic_type = true;
+    bool is_predicate_column_exists = false;
+    bool is_non_predicate_column_exists = false;
+    
+    if (!_col_predicates.empty()) {
+        is_predicate_column_exists = true;
+
+        std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+        std::set<ColumnId> vec_pred_col_id_set;
+        
+        for (auto predicate : _col_predicates) {
+            auto cid = predicate->column_id();
+            FieldType type = _schema.column(cid)->type();
+            _is_pred_column[cid] = true;
+            pred_column_ids.insert(cid);
+
+            // for date type which can not be executed in a vectorized way, using short circuit execution
+            if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+                || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+                short_cir_pred_col_id_set.insert(cid);
+                _short_cir_eval_predicate.push_back(predicate);
+                _is_all_column_basic_type = false;
+            } else {
+                vec_pred_col_id_set.insert(predicate->column_id());
+                if (_pre_eval_block_predicate == nullptr) {
+                    _pre_eval_block_predicate = new AndBlockColumnPredicate();
+                }
+                reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+            }
+        }
+
+        std::set<ColumnId> del_cond_id_set;
+        _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+        short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+        pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+        if (_schema.column_ids().size() > pred_column_ids.size()) {
+            for (auto cid : _schema.column_ids()) {
+                if (!_is_pred_column[cid]) {
+                    _non_predicate_columns.push_back(cid);
+                    is_non_predicate_column_exists = true;
+                }
+            }
+        }
+
+        _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+        _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+    } else {
+        _is_all_column_basic_type = false;
+        is_non_predicate_column_exists = true;
+        for (auto cid : _schema.column_ids()) {
+            _non_predicate_columns.push_back(cid);
+        }
+    }
+
+    // note(wb) in following cases we disable lazy materialization
+    // case 1: when all column is basic type(is_all_column_basic_type = true) 
+    //   because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+    // case 2: all column is predicate column
+    // case 3: all column is not predicate column
+    // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+    if (_is_all_column_basic_type) {
+        std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+        std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+        // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+        for (int i = 0; i < _schema.num_column_ids(); i++) {
+            auto cid = _schema.column_ids()[i];
+            if (pred_set.find(cid) != pred_set.end()) {
+                _first_read_column_ids.push_back(cid);    
+            } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+                _first_read_column_ids.push_back(cid);
+                _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+            }
+        }
+
+    } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+        _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+    } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+        for (auto cid : _non_predicate_columns) {
+            _first_read_column_ids.push_back(cid);
+        }
+    } else {
+        _lazy_materialization_read = true;
+        _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+    }
+
+    // make _schema_block_id_map
+    _schema_block_id_map.resize(_schema.columns().size());
+    for (int i = 0; i < _schema.num_column_ids(); i++) {
+        auto cid = _schema.column_ids()[i];
+        _schema_block_id_map[cid] = i;
+    }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+    for (auto cid : column_ids) {
+        auto& column = column_block[cid];
+        size_t rows_read = nrows;
+        RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+        DCHECK_EQ(nrows, rows_read);
+    }
+    return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+    bool is_block_mem_reuse= block->mem_reuse();
+    if (is_block_mem_reuse) {
+        size_t column_to_keep = _schema.num_column_ids();
+        for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+            block->erase(i);
+        }
+        block->clear_column_data();
+    } else { // pre fill output block here
+        for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+            auto cid = _schema.column_ids()[i];
+            auto* column_desc = _schema.columns()[cid];
+            auto data_type = Schema::get_data_type_ptr(column_desc->type());
+            if (column_desc->is_nullable()) {
+                block->insert({nullptr, std::make_shared<vectorized::DataTypeNullable>(std::move(data_type)), column_desc->name()});
+            } else {
+                block->insert({nullptr, std::move(data_type), column_desc->name()});
+            }
+        }
+    }
+
+    for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+        auto cid = _schema.column_ids()[i];
+        if (_is_pred_column[cid]) {  //todo(wb) maybe we can relase it after output block
+            current_columns[cid]->clear();
+        } else { // non-predicate column
+            auto &column_desc = _schema.columns()[cid];
+            if (is_block_mem_reuse) {
+                current_columns[cid] = std::move(*block->get_by_position(i).column).mutate();
+            } else {
+                auto data_type = Schema::get_data_type_ptr(column_desc->type());
+                if (column_desc->is_nullable()) {
+                    current_columns[cid] = doris::vectorized::ColumnNullable::create(
+                        std::move(data_type->create_column()), doris::vectorized::ColumnUInt8::create());
+                } else {
+                    current_columns[cid] = data_type->create_column();
+                }
+            }
+            if (column_desc->type() == OLAP_FIELD_TYPE_DATE) {
+                current_columns[cid]->set_date_type();
+            } else if (column_desc->type() == OLAP_FIELD_TYPE_DATETIME) {
+                current_columns[cid]->set_datetime_type();
+            }
+        }
+    }
+}
+
+void SegmentIterator::_output_non_pred_columns(vectorized::Block* block, bool is_block_mem_reuse) {
+    for (auto cid : _non_predicate_columns) {
+        block->replace_by_position(_schema_block_id_map[cid], std::move(_current_return_columns[cid]));
+    }
+ }
+
+void SegmentIterator::_output_column_by_sel_idx(vectorized::Block* block, std::vector<ColumnId> columnIds, 
+        uint16_t* sel_rowid_idx, uint16_t select_size, bool is_block_mem_reuse) {
+    for (auto cid : columnIds) {
+        auto &column_ptr = _current_return_columns[cid];
+        if (is_block_mem_reuse) {
+            column_ptr->filter_by_selector(sel_rowid_idx, select_size, 
+                &block->get_by_position(_schema_block_id_map[cid]).column);
+        } else {
+            block->replace_by_position(_schema_block_id_map[cid], 
+                (*column_ptr).get_ptr()->filter_by_selector(sel_rowid_idx, select_size));
+        }
+    }
+ }
+
+
+Status SegmentIterator::_read_columns_by_index(uint32_t nrows_read_limit, uint32_t& nrows_read, bool set_block_rowid) {
+    do {
+        uint32_t range_from;
+        uint32_t range_to;
+        bool has_next_range =
+            _range_iter->next_range(nrows_read_limit - nrows_read, &range_from, &range_to);
+        if (!has_next_range) {
+            break;
+        }
+        if (_cur_rowid == 0 || _cur_rowid != range_from) {
+            _cur_rowid = range_from;
+            RETURN_IF_ERROR(_seek_columns(_first_read_column_ids, _cur_rowid));
+        }
+        size_t rows_to_read = range_to - range_from;
+        RETURN_IF_ERROR(_read_columns(_first_read_column_ids, _current_return_columns, rows_to_read));
+        _cur_rowid += rows_to_read;
+        if (set_block_rowid) {
+            for (uint32_t rid = range_from; rid < range_to; rid++) {
+                _block_rowids[nrows_read++] = rid;
+            }
+        } else {
+            nrows_read += rows_to_read;
+        }
+    } while (nrows_read < nrows_read_limit);
+    return Status::OK();
+}
+
+void SegmentIterator::_evaluate_vectorization_predicate(uint16_t* sel_rowid_idx, uint16_t& selected_size) {
+    uint16_t new_size = 0;
+    if (_vec_pred_column_ids.size() == 0) {
+        for (uint32_t i = 0; i < selected_size; ++i) {
+            sel_rowid_idx[new_size++] = i;
+        }
+        return;
+    }
+
+    uint16_t original_size = selected_size;
+    bool ret_flags[selected_size];
+    memset(ret_flags, 1, selected_size);
+    _pre_eval_block_predicate->evaluate_vec(_current_return_columns, selected_size, ret_flags);
+    
+    for (uint32_t i = 0; i < selected_size; ++i) {
+        if (ret_flags[i]) {
+            sel_rowid_idx[new_size++] = i;
+        }
+    }
+
+    _opts.stats->rows_vec_cond_filtered += original_size - new_size;
+    selected_size = new_size;
+}
+
+void SegmentIterator::_evaluate_short_circuit_predicate(uint16_t* vec_sel_rowid_idx, uint16_t* selected_size_ptr) {
+    if (_short_cir_pred_column_ids.size() == 0) {
+        return;
+    }
+    
+    for (auto column_predicate : _short_cir_eval_predicate) {
+        auto column_id = column_predicate->column_id();
+        auto& short_cir_column = _current_return_columns[column_id];
+        column_predicate->evaluate(*short_cir_column, vec_sel_rowid_idx, selected_size_ptr);
+    }
+
+    // evaluate delete condition
+    _opts.delete_condition_predicates->evaluate(_current_return_columns, vec_sel_rowid_idx, selected_size_ptr);
+}
+
+void SegmentIterator::_read_columns_by_rowids(std::vector<ColumnId>& read_column_ids, std::vector<rowid_t>& rowid_vector,
+        uint16_t* sel_rowid_idx, size_t select_size, vectorized::MutableColumns* mutable_columns) {
+    size_t start_idx = 0;
+    while (start_idx < select_size) {
+        size_t end_idx = start_idx + 1;
+        while (end_idx < select_size && (rowid_vector[sel_rowid_idx[end_idx - 1]] == rowid_vector[sel_rowid_idx[end_idx]] - 1)) {
+            end_idx++;
+        }
+        size_t range = end_idx - start_idx;
+        _seek_columns(read_column_ids, rowid_vector[sel_rowid_idx[start_idx]]);
+        _read_columns(read_column_ids, *mutable_columns, range);
+        start_idx += range;
+    }
+}
+
+Status SegmentIterator::next_batch(vectorized::Block* block) {
+    bool is_mem_reuse = block->mem_reuse();
+    SCOPED_RAW_TIMER(&_opts.stats->block_load_ns);
+    if (UNLIKELY(!_inited)) {
+        RETURN_IF_ERROR(_init(true));
+        _inited = true;
+        if (_vec_pred_column_ids.size() > 0 || _short_cir_pred_column_ids.size() > 0) {
+            _block_rowids.reserve(_opts.block_row_max);
+        }
+        _current_return_columns.resize(_schema.columns().size()); 
+        for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+            auto cid = _schema.column_ids()[i];
+            if (_is_pred_column[cid]) {
+                auto& column_desc = _schema.columns()[cid];
+                _current_return_columns[cid] = Schema::get_predicate_column_nullable_ptr(column_desc->type(), column_desc->is_nullable());
+                _current_return_columns[cid]->reserve(_opts.block_row_max);
+            }
+        }
+    }
+
+    _init_current_block(block, _current_return_columns);
+    
+    uint32_t nrows_read = 0;
+    uint32_t nrows_read_limit = _opts.block_row_max;
+    _read_columns_by_index(nrows_read_limit, nrows_read, _col_predicates.size() > 0);
+
+    _opts.stats->blocks_load += 1;
+    _opts.stats->raw_rows_read += nrows_read;
+
+    if (nrows_read == 0) {
+        for (int i = 0; i < _schema.num_column_ids(); i++) {
+            auto cid = _schema.column_ids()[i];
+            // todo(wb) abstract make column where
+            if (!_is_pred_column[cid]) { // non-predicate
+                block->replace_by_position(i, std::move(_current_return_columns[cid]));
+            } else { // predicate
+                if (!is_mem_reuse) {
+                    auto* column_desc = _schema.columns()[cid];
+                    auto data_type = Schema::get_data_type_ptr(column_desc->type());
+                    block->replace_by_position(i, data_type->create_column());
+                }
+            }
+            // not sure whether block is clear before enter segmentIter, so clear it here.
+            if (is_mem_reuse) {
+                block->clear_column_data();
+            }
+        }
+        return Status::EndOfFile("no more data in segment");
+    }
+
+    // when no predicate(include delete condition) is provided, output column directly
+    if (_vec_pred_column_ids.size() == 0 && _short_cir_pred_column_ids.size() == 0) {
+        _output_non_pred_columns(block, is_mem_reuse);
+    } else { // need predicate evaluation
+        uint16_t selected_size = nrows_read;
+        uint16_t sel_rowid_idx[selected_size];
+
+        // step 1: evaluate vectorization predicate
+        _evaluate_vectorization_predicate(sel_rowid_idx, selected_size);
+
+        // When predicate column and no-predicate column are both basic type, lazy materialization is eliminate
+        // So output block directly after vecorization evaluation
+        if (_is_all_column_basic_type) {
+            _output_column_by_sel_idx(block, _first_read_column_ids, sel_rowid_idx, selected_size, is_mem_reuse);
+            return Status::OK();
+        }
+
+        // step 2: evaluate short ciruit predicate
+        // todo(wb) research whether need to read short predicate after vectorization evaluation
+        //          to reduce cost of read short circuit columns.
+        //          In SSB test, it make no difference; So need more scenarios to test
+        _evaluate_short_circuit_predicate(sel_rowid_idx, &selected_size);
+        
+        // step3: read non_predicate column
+        if (_non_predicate_columns.size() != 0) {
+            _read_columns_by_rowids(_non_predicate_columns, _block_rowids, sel_rowid_idx, selected_size, &_current_return_columns);
+        }
+
+        // step4: output columns
+        // 4.1 output non-predicate column
+        _output_non_pred_columns(block, is_mem_reuse);
+
+        // 4.2 output short circuit predicate column
+        _output_column_by_sel_idx(block, _short_cir_pred_column_ids, sel_rowid_idx, selected_size, is_mem_reuse);
+        // 4.3 output vectorizatioin predicate column
+        _output_column_by_sel_idx(block, _vec_pred_column_ids, sel_rowid_idx, selected_size, is_mem_reuse);
+
+    }
+
+    return Status::OK();
+}
+
 } // namespace segment_v2
 } // namespace doris
diff --git a/be/src/olap/rowset/segment_v2/segment_iterator.h b/be/src/olap/rowset/segment_v2/segment_iterator.h
index 0da6ae4..c06077e 100644
--- a/be/src/olap/rowset/segment_v2/segment_iterator.h
+++ b/be/src/olap/rowset/segment_v2/segment_iterator.h
@@ -50,14 +50,17 @@ public:
     SegmentIterator(std::shared_ptr<Segment> segment, const Schema& _schema,
                     std::shared_ptr<MemTracker> parent);
     ~SegmentIterator() override;
+
     Status init(const StorageReadOptions& opts) override;
     Status next_batch(RowBlockV2* row_block) override;
+    Status next_batch(vectorized::Block* block) override;
+
     const Schema& schema() const override { return _schema; }
     bool is_lazy_materialization_read() const override { return _lazy_materialization_read; }
     uint64_t data_id() const { return _segment->id(); }
 
 private:
-    Status _init();
+    Status _init(bool is_vec = false);
 
     Status _init_return_column_iterators();
     Status _init_bitmap_index_iterators();
@@ -75,6 +78,7 @@ private:
     Status _apply_bitmap_index();
 
     void _init_lazy_materialization();
+    void _vec_init_lazy_materialization();
 
     uint32_t segment_id() const { return _segment->id(); }
     uint32_t num_rows() const { return _segment->num_rows(); }
@@ -84,6 +88,17 @@ private:
     Status _read_columns(const std::vector<ColumnId>& column_ids, RowBlockV2* block,
                          size_t row_offset, size_t nrows);
 
+    // for vectorization implementation
+    Status _read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows);
+    Status _read_columns_by_index(uint32_t nrows_read_limit, uint32_t& nrows_read, bool set_block_rowid);
+    void _init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& non_pred_vector);
+    void _evaluate_vectorization_predicate(uint16_t* sel_rowid_idx, uint16_t& selected_size);
+    void _evaluate_short_circuit_predicate(uint16_t* sel_rowid_idx, uint16_t* selected_size);
+    void _output_non_pred_columns(vectorized::Block* block, bool is_block_mem_reuse);
+    void _output_column_by_sel_idx(vectorized::Block* block, std::vector<ColumnId> columnids, uint16_t* sel_rowid_idx, uint16_t select_size, bool is_block_mem_reuse);
+    void _read_columns_by_rowids(std::vector<ColumnId>& read_column_ids, std::vector<rowid_t>& rowid_vector, 
+        uint16_t* sel_rowid_idx, size_t select_size, vectorized::MutableColumns* mutable_columns);
+
 private:
     class BitmapRangeIterator;
 
@@ -113,6 +128,21 @@ private:
     // could be a local variable of next_batch(), kept here to reuse vector memory
     std::vector<rowid_t> _block_rowids;
 
+    // fields for vectorization execution 
+    bool _is_all_column_basic_type;
+    std::vector<ColumnId> _vec_pred_column_ids; // keep columnId of columns for vectorized predicate evaluation
+    std::vector<ColumnId> _short_cir_pred_column_ids; // keep columnId of columns for short circuit predicate evaluation
+    vector<bool> _is_pred_column; // columns hold by segmentIter
+    vectorized::MutableColumns _current_return_columns;
+    AndBlockColumnPredicate* _pre_eval_block_predicate = nullptr;
+    std::vector<ColumnPredicate*> _short_cir_eval_predicate;
+    // when lazy materialization is enable, segmentIter need to read data at least twice
+    // first, read predicate columns by various index
+    // second, read non-predicate columns
+    // so we need a field to stand for columns first time to read
+    vector<ColumnId> _first_read_column_ids;
+    vector<int> _schema_block_id_map; // map from schema column id to column idx in Block
+
     // the actual init process is delayed to the first call to next_batch()
     bool _inited;
 
diff --git a/be/src/olap/schema.cpp b/be/src/olap/schema.cpp
index ab00e37..f5a0900 100644
--- a/be/src/olap/schema.cpp
+++ b/be/src/olap/schema.cpp
@@ -18,6 +18,11 @@
 #include "olap/schema.h"
 
 #include "olap/row_block2.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/columns/column_complex.h"
+#include "vec/columns/predicate_column.h"
+#include "vec/core/types.h"
+#include "olap/uint24.h"
 
 namespace doris {
 
@@ -103,4 +108,109 @@ Schema::~Schema() {
     }
 }
 
+vectorized::DataTypePtr Schema::get_data_type_ptr(FieldType type) {
+    switch (type) {
+        case OLAP_FIELD_TYPE_BOOL:
+            return std::make_shared<vectorized::DataTypeUInt8>();
+
+        case OLAP_FIELD_TYPE_TINYINT:
+            return std::make_shared<vectorized::DataTypeInt8>();
+
+        case OLAP_FIELD_TYPE_SMALLINT:
+            return std::make_shared<vectorized::DataTypeInt16>();
+
+        case OLAP_FIELD_TYPE_INT:
+            return std::make_shared<vectorized::DataTypeInt32>();
+
+        case OLAP_FIELD_TYPE_FLOAT:
+            return std::make_shared<vectorized::DataTypeFloat32>();
+
+        case OLAP_FIELD_TYPE_BIGINT:
+            return std::make_shared<vectorized::DataTypeInt64>();
+
+        case OLAP_FIELD_TYPE_LARGEINT:
+            return std::make_shared<vectorized::DataTypeInt128>();
+
+        case OLAP_FIELD_TYPE_DATE:
+            return std::make_shared<vectorized::DataTypeDate>();
+
+        case OLAP_FIELD_TYPE_DATETIME:
+            return std::make_shared<vectorized::DataTypeDateTime>();
+
+        case OLAP_FIELD_TYPE_DOUBLE:
+            return std::make_shared<vectorized::DataTypeFloat64>();
+
+        case OLAP_FIELD_TYPE_CHAR:
+        case OLAP_FIELD_TYPE_VARCHAR:
+        case OLAP_FIELD_TYPE_HLL:
+        case OLAP_FIELD_TYPE_STRING:
+            return std::make_shared<vectorized::DataTypeString>();
+        
+        case TYPE_OBJECT:
+            return std::make_shared<vectorized::DataTypeBitMap>();
+
+        case OLAP_FIELD_TYPE_DECIMAL:
+            return std::make_shared<vectorized::DataTypeDecimal<vectorized::Decimal128>>(27, 9);
+
+        default:
+            DCHECK(false);
+    }
+    // For llvm complain
+    return nullptr;
+}
+
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_nullable_ptr(FieldType type, bool is_null) {
+    vectorized::IColumn::MutablePtr ptr = Schema::get_predicate_column_ptr(type);
+    if (is_null) {
+        return doris::vectorized::ColumnNullable::create(std::move(ptr), doris::vectorized::ColumnUInt8::create());
+    }
+    return ptr;
+}
+
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_ptr(FieldType type) {
+    switch (type) {
+        case OLAP_FIELD_TYPE_BOOL:
+            return doris::vectorized::PredicateColumnType<bool>::create();;
+        case OLAP_FIELD_TYPE_TINYINT:
+            return doris::vectorized::PredicateColumnType<doris::vectorized::Int8>::create();
+ 
+        case OLAP_FIELD_TYPE_SMALLINT:
+            return doris::vectorized::PredicateColumnType<doris::vectorized::Int16>::create();
+ 
+        case OLAP_FIELD_TYPE_INT:
+            return doris::vectorized::PredicateColumnType<doris::vectorized::Int32>::create();
+ 
+        case OLAP_FIELD_TYPE_FLOAT:
+            return doris::vectorized::PredicateColumnType<doris::vectorized::Float32>::create();
+ 
+        case OLAP_FIELD_TYPE_DOUBLE:
+            return doris::vectorized::PredicateColumnType<doris::vectorized::Float64>::create();
+ 
+        case OLAP_FIELD_TYPE_BIGINT:
+            return doris::vectorized::PredicateColumnType<doris::vectorized::Int64>::create();
+ 
+        case OLAP_FIELD_TYPE_LARGEINT:
+            return doris::vectorized::PredicateColumnType<doris::vectorized::Int128>::create();
+ 
+        case OLAP_FIELD_TYPE_DATE:
+            return doris::vectorized::PredicateColumnType<uint24_t>::create();
+
+        case OLAP_FIELD_TYPE_DATETIME:
+            return doris::vectorized::PredicateColumnType<uint64_t>::create();
+ 
+        case OLAP_FIELD_TYPE_CHAR:
+        case OLAP_FIELD_TYPE_VARCHAR: 
+        case OLAP_FIELD_TYPE_STRING:
+            return doris::vectorized::PredicateColumnType<StringValue>::create();
+        
+        case OLAP_FIELD_TYPE_DECIMAL:
+            return doris::vectorized::PredicateColumnType<decimal12_t>::create();    
+ 
+        default:
+            DCHECK(false);
+    }
+    // For llvm complain
+    return nullptr;
+}
+
 } // namespace doris
diff --git a/be/src/olap/schema.h b/be/src/olap/schema.h
index 39e3c79..2596f97 100644
--- a/be/src/olap/schema.h
+++ b/be/src/olap/schema.h
@@ -100,6 +100,14 @@ public:
 
     ~Schema();
 
+    static vectorized::DataTypePtr get_data_type_ptr(FieldType type);
+
+    static vectorized::IColumn::MutablePtr get_predicate_column_ptr(FieldType type);
+
+    static vectorized::IColumn::MutablePtr get_predicate_column_nullable_ptr(FieldType type, bool is_null = false);
+
+    const std::vector<Field*>& columns() const { return _cols; }
+
     const Field* column(ColumnId cid) const { return _cols[cid]; }
 
     Field* mutable_column(ColumnId cid) const { return _cols[cid]; }
diff --git a/be/src/olap/tablet_schema.cpp b/be/src/olap/tablet_schema.cpp
index 072a415..5b407d5 100644
--- a/be/src/olap/tablet_schema.cpp
+++ b/be/src/olap/tablet_schema.cpp
@@ -18,6 +18,8 @@
 #include "olap/tablet_schema.h"
 
 #include "tablet_meta.h"
+#include "vec/core/block.h"
+#include "vec/data_types/data_type.h"
 
 namespace doris {
 
@@ -490,6 +492,16 @@ void TabletSchema::init_field_index_for_test() {
     }
 }
 
+vectorized::Block TabletSchema::create_block(const std::vector<uint32_t>& return_columns) const {
+    vectorized::Block block;
+    for (int i = 0; i < return_columns.size(); ++i) {
+        const auto& col = _cols[return_columns[i]];
+        auto data_type = vectorized::IDataType::from_olap_engine(col.type(), col.is_nullable());
+        block.insert({data_type->create_column(), data_type, col.name()});
+    }
+    return block;
+}
+
 bool operator==(const TabletColumn& a, const TabletColumn& b) {
     if (a._unique_id != b._unique_id) return false;
     if (a._col_name != b._col_name) return false;
@@ -548,4 +560,5 @@ bool operator!=(const TabletSchema& a, const TabletSchema& b) {
     return !(a == b);
 }
 
+
 } // namespace doris
diff --git a/be/src/olap/tablet_schema.h b/be/src/olap/tablet_schema.h
index 0cb894f..ffd8c34 100644
--- a/be/src/olap/tablet_schema.h
+++ b/be/src/olap/tablet_schema.h
@@ -26,6 +26,9 @@
 #include "olap/types.h"
 
 namespace doris {
+namespace vectorized {
+class Block;
+}
 
 class TabletColumn {
 public:
@@ -141,6 +144,7 @@ public:
     inline void set_delete_sign_idx(int32_t delete_sign_idx) { _delete_sign_idx = delete_sign_idx; }
     inline bool has_sequence_col() const { return _sequence_col_idx != -1; }
     inline int32_t sequence_col_idx() const { return _sequence_col_idx; }
+    vectorized::Block create_block(const std::vector<uint32_t>& return_columns) const;
 
 private:
     // Only for unit test
diff --git a/be/src/olap/tuple_reader.cpp b/be/src/olap/tuple_reader.cpp
index 9eba1d2..5c15c2b 100644
--- a/be/src/olap/tuple_reader.cpp
+++ b/be/src/olap/tuple_reader.cpp
@@ -196,7 +196,7 @@ OLAPStatus TupleReader::_unique_key_next_row(RowCursor* row_cursor, MemPool* mem
             cur_delete_flag = _next_delete_flag;
         }
 
-        // if reader needs to filter delete row and current delete_flag is ture,
+        // if reader needs to filter delete row and current delete_flag is true,
         // then continue
         if (!(cur_delete_flag && _filter_delete)) {
             break;
diff --git a/be/src/runtime/datetime_value.cpp b/be/src/runtime/datetime_value.cpp
index 9ec8ccb..b545f55 100644
--- a/be/src/runtime/datetime_value.cpp
+++ b/be/src/runtime/datetime_value.cpp
@@ -1466,6 +1466,8 @@ bool DateTimeValue::from_date_format_str(const char* format, int format_len, con
 }
 
 bool DateTimeValue::date_add_interval(const TimeInterval& interval, TimeUnit unit) {
+    if (!is_valid_date()) return false;
+
     int sign = interval.is_neg ? -1 : 1;
     switch (unit) {
     case MICROSECOND:
diff --git a/be/src/runtime/datetime_value.h b/be/src/runtime/datetime_value.h
index 096a24d..4f3a310 100644
--- a/be/src/runtime/datetime_value.h
+++ b/be/src/runtime/datetime_value.h
@@ -30,7 +30,7 @@
 #include "udf/udf.h"
 #include "util/hash_util.hpp"
 #include "util/timezone_utils.h"
-
+#include "vec/runtime/vdatetime_value.h"
 namespace doris {
 
 enum TimeUnit {
@@ -566,7 +566,9 @@ public:
 private:
     // Used to make sure sizeof DateTimeValue
     friend class UnusedClass;
-
+    friend void doris::vectorized::VecDateTimeValue::convert_vec_dt_to_dt(DateTimeValue* dt); 
+    friend void doris::vectorized::VecDateTimeValue::convert_dt_to_vec_dt(DateTimeValue* dt);
+    
     void from_packed_time(int64_t packed_time) {
         _microsecond = packed_time % (1LL << 24);
         int64_t ymdhms = packed_time >> 24;
diff --git a/be/src/runtime/descriptors.cpp b/be/src/runtime/descriptors.cpp
index ab4fa97..95d0a79 100644
--- a/be/src/runtime/descriptors.cpp
+++ b/be/src/runtime/descriptors.cpp
@@ -25,6 +25,10 @@
 #include "gen_cpp/Descriptors_types.h"
 #include "gen_cpp/descriptors.pb.h"
 
+#include "vec/core/columns_with_type_and_name.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/data_types/data_type_nullable.h"
+
 namespace doris {
 using boost::algorithm::join;
 
@@ -80,6 +84,21 @@ void SlotDescriptor::to_protobuf(PSlotDescriptor* pslot) const {
     pslot->set_is_materialized(_is_materialized);
 }
 
+vectorized::MutableColumnPtr SlotDescriptor::get_empty_mutable_column() const {
+    auto data_column = type().get_data_type_ptr()->create_column();
+    if (is_nullable()) {
+        return doris::vectorized::ColumnNullable::create(std::move(data_column), doris::vectorized::ColumnUInt8::create());
+    }
+    return data_column;
+}
+
+vectorized::DataTypePtr SlotDescriptor::get_data_type_ptr() const {
+    if (is_nullable()) {
+        return std::make_shared<vectorized::DataTypeNullable>(type().get_data_type_ptr());
+    }
+    return type().get_data_type_ptr();
+}
+
 std::string SlotDescriptor::debug_string() const {
     std::stringstream out;
     out << "Slot(id=" << _id << " type=" << _type << " col=" << _col_pos
@@ -378,7 +397,7 @@ void RowDescriptor::to_thrift(std::vector<TTupleId>* row_tuple_ids) {
 }
 
 void RowDescriptor::to_protobuf(
-        google::protobuf::RepeatedField<google::protobuf::int32>* row_tuple_ids) {
+        google::protobuf::RepeatedField<google::protobuf::int32>* row_tuple_ids) const {
     row_tuple_ids->Clear();
     for (auto desc : _tuple_desc_map) {
         row_tuple_ids->Add(desc->id());
diff --git a/be/src/runtime/descriptors.h b/be/src/runtime/descriptors.h
index d668d42..ad43209 100644
--- a/be/src/runtime/descriptors.h
+++ b/be/src/runtime/descriptors.h
@@ -103,6 +103,9 @@ public:
 
     std::string debug_string() const;
 
+    doris::vectorized::MutableColumnPtr get_empty_mutable_column() const;
+
+    doris::vectorized::DataTypePtr get_data_type_ptr() const;
 private:
     friend class DescriptorTbl;
     friend class TupleDescriptor;
@@ -378,7 +381,6 @@ public:
     int get_row_size() const;
 
     int num_materialized_slots() const {
-        DCHECK(_num_materialized_slots != 0);
         return _num_materialized_slots;
     }
 
@@ -405,7 +407,7 @@ public:
 
     // Populate row_tuple_ids with our ids.
     void to_thrift(std::vector<TTupleId>* row_tuple_ids);
-    void to_protobuf(google::protobuf::RepeatedField<google::protobuf::int32>* row_tuple_ids);
+    void to_protobuf(google::protobuf::RepeatedField<google::protobuf::int32>* row_tuple_ids) const;
 
     // Return true if the tuple ids of this descriptor are a prefix
     // of the tuple ids of other_desc.
diff --git a/be/src/runtime/exec_env.h b/be/src/runtime/exec_env.h
index 3cc2def..0b51e47 100644
--- a/be/src/runtime/exec_env.h
+++ b/be/src/runtime/exec_env.h
@@ -93,6 +93,7 @@ public:
     const std::string& token() const;
     ExternalScanContextMgr* external_scan_context_mgr() { return _external_scan_context_mgr; }
     DataStreamMgr* stream_mgr() { return _stream_mgr; }
+    doris::vectorized::VDataStreamMgr* vstream_mgr() { return _vstream_mgr; }
     ResultBufferMgr* result_mgr() { return _result_mgr; }
     ResultQueueMgr* result_queue_mgr() { return _result_queue_mgr; }
     ClientCache<BackendServiceClient>* client_cache() { return _backend_client_cache; }
@@ -163,6 +164,7 @@ private:
     // Leave protected so that subclasses can override
     ExternalScanContextMgr* _external_scan_context_mgr = nullptr;
     DataStreamMgr* _stream_mgr = nullptr;
+    doris::vectorized::VDataStreamMgr* _vstream_mgr = nullptr;
     ResultBufferMgr* _result_mgr = nullptr;
     ResultQueueMgr* _result_queue_mgr = nullptr;
     ClientCache<BackendServiceClient>* _backend_client_cache = nullptr;
diff --git a/be/src/runtime/exec_env_init.cpp b/be/src/runtime/exec_env_init.cpp
index a172bb6..35630d0 100644
--- a/be/src/runtime/exec_env_init.cpp
+++ b/be/src/runtime/exec_env_init.cpp
@@ -63,6 +63,7 @@
 #include "util/parse_util.h"
 #include "util/pretty_printer.h"
 #include "util/priority_thread_pool.hpp"
+#include "vec/runtime/vdata_stream_mgr.h"
 
 namespace doris {
 
@@ -85,6 +86,7 @@ Status ExecEnv::_init(const std::vector<StorePath>& store_paths) {
     _store_paths = store_paths;
     _external_scan_context_mgr = new ExternalScanContextMgr(this);
     _stream_mgr = new DataStreamMgr();
+    _vstream_mgr = new doris::vectorized::VDataStreamMgr();
     _result_mgr = new ResultBufferMgr();
     _result_queue_mgr = new ResultQueueMgr();
     _backend_client_cache = new BackendServiceClientCache(config::max_client_cache_size_per_host);
diff --git a/be/src/runtime/fold_constant_executor.cpp b/be/src/runtime/fold_constant_executor.cpp
index 94d3d9e..f093c04 100644
--- a/be/src/runtime/fold_constant_executor.cpp
+++ b/be/src/runtime/fold_constant_executor.cpp
@@ -28,6 +28,9 @@
 #include "common/object_pool.h"
 #include "common/status.h"
 
+#include "vec/exprs/vexpr.h"
+#include "vec/exprs/vexpr_context.h"
+
 #include "gen_cpp/internal_service.pb.h"
 #include "gen_cpp/PaloInternalService_types.h"
 
@@ -79,7 +82,7 @@ Status FoldConstantExecutor::fold_constant_expr(
                 expr_result.set_success(false);
             } else {
                 expr_result.set_success(true);
-                result = _get_result(src, ctx->root()->type().type);
+                result = _get_result(src, 0, ctx->root()->type().type);
             }
 
             expr_result.set_content(std::move(result));
@@ -96,6 +99,69 @@ Status FoldConstantExecutor::fold_constant_expr(
     return Status::OK();
 }
 
+Status FoldConstantExecutor::fold_constant_vexpr(
+        const TFoldConstantParams& params, PConstantExprResult* response) {
+    const auto& expr_map = params.expr_map;
+    auto expr_result_map = response->mutable_expr_result_map();
+
+    TQueryGlobals query_globals = params.query_globals;
+    // init
+    Status status = _init(query_globals);
+    if (UNLIKELY(!status.ok())) {
+        LOG(WARNING) << "Failed to init mem trackers, msg: " << status.get_error_msg();
+        return status;
+    }
+
+    for (const auto& m : expr_map) {
+        PExprResultMap pexpr_result_map;
+        for (const auto& n : m.second) {
+            vectorized::VExprContext* ctx = nullptr;
+            const TExpr& texpr = n.second;
+            // create expr tree from TExpr
+            RETURN_IF_ERROR(vectorized::VExpr::create_expr_tree(&_pool, texpr, &ctx));
+            // prepare and open context
+            status = _prepare_and_open(ctx);
+            if (UNLIKELY(!status.ok())) {
+                LOG(WARNING) << "Failed to init mem trackers, msg: " << status.get_error_msg();
+                return status;
+            }
+
+            vectorized::Block tmp_block;
+            tmp_block.insert({vectorized::ColumnUInt8::create(1),
+                    std::make_shared<vectorized::DataTypeUInt8>(), ""});
+            int result_column = -1;
+            // calc vexpr
+            RETURN_IF_ERROR(ctx->execute(&tmp_block, &result_column));
+            DCHECK(result_column != -1);
+            PrimitiveType root_type = ctx->root()->type().type;
+            // covert to thrift type
+            TPrimitiveType::type t_type = doris::to_thrift(root_type);
+
+            // collect result
+            PExprResult expr_result;
+            string result;
+            const auto& column_ptr = tmp_block.get_by_position(result_column).column;
+            if (column_ptr->is_null_at(0)) {
+                expr_result.set_success(false);
+            } else {
+                expr_result.set_success(true);
+                auto string_ref = column_ptr->get_data_at(0);
+                result = _get_result<true>((void*)string_ref.data, string_ref.size, ctx->root()->type().type);
+            }
+
+            expr_result.set_content(std::move(result));
+            expr_result.mutable_type()->set_type(t_type);
+            pexpr_result_map.mutable_map()->insert({n.first, expr_result});
+
+            // close context expr
+            ctx->close(_runtime_state.get());
+        }
+        expr_result_map->insert({m.first, pexpr_result_map});
+    }
+
+    return Status::OK();
+}
+
 Status FoldConstantExecutor::_init(const TQueryGlobals& query_globals) {
     // init runtime state, runtime profile
     TPlanFragmentExecParams params;
@@ -128,12 +194,14 @@ Status FoldConstantExecutor::_init(const TQueryGlobals& query_globals) {
     return Status::OK();
 }
 
-Status FoldConstantExecutor::_prepare_and_open(ExprContext* ctx) {
-    ctx->prepare(_runtime_state.get(), RowDescriptor(), _mem_tracker);
+template <typename Context>
+Status FoldConstantExecutor::_prepare_and_open(Context* ctx) {
+    RETURN_IF_ERROR(ctx->prepare(_runtime_state.get(), RowDescriptor(), _mem_tracker));
     return ctx->open(_runtime_state.get());
 }
 
-string FoldConstantExecutor::_get_result(void* src, PrimitiveType slot_type){
+template <bool is_vec>
+string FoldConstantExecutor::_get_result(void* src, size_t size, PrimitiveType slot_type){
     switch (slot_type) {
     case TYPE_BOOLEAN: {
         bool val = *reinterpret_cast<const bool*>(src);
@@ -172,14 +240,24 @@ string FoldConstantExecutor::_get_result(void* src, PrimitiveType slot_type){
     case TYPE_STRING:
     case TYPE_HLL:
     case TYPE_OBJECT: {
+        if constexpr (is_vec) {
+            return std::string((char*)src, size);
+        }
         return (reinterpret_cast<StringValue*>(src))->to_string();
     }
     case TYPE_DATE:
     case TYPE_DATETIME: {
-        const DateTimeValue date_value = *reinterpret_cast<DateTimeValue*>(src);
-        char str[MAX_DTVALUE_STR_LEN];
-        date_value.to_string(str);
-        return str;
+        if constexpr (is_vec) {
+            auto date_value = reinterpret_cast<vectorized::VecDateTimeValue*>(src);
+            char str[MAX_DTVALUE_STR_LEN];
+            date_value->to_string(str);
+            return str;
+        } else {
+            const DateTimeValue date_value = *reinterpret_cast<DateTimeValue *>(src);
+            char str[MAX_DTVALUE_STR_LEN];
+            date_value.to_string(str);
+            return str;
+        }
     }
     case TYPE_DECIMALV2: {
         return reinterpret_cast<DecimalV2Value*>(src)->to_string();
diff --git a/be/src/runtime/fold_constant_executor.h b/be/src/runtime/fold_constant_executor.h
index 93ee988..84c52f7 100644
--- a/be/src/runtime/fold_constant_executor.h
+++ b/be/src/runtime/fold_constant_executor.h
@@ -36,13 +36,18 @@ class FoldConstantExecutor {
 public:
     // fold constant expr
     Status fold_constant_expr(const TFoldConstantParams& params, PConstantExprResult* response);
+
+    // fold constant vexpr
+    Status fold_constant_vexpr(const TFoldConstantParams& params, PConstantExprResult* response);
 private:
     // init runtime_state and mem_tracker
     Status _init(const TQueryGlobals& query_globals);
     // prepare expr
-    Status _prepare_and_open(ExprContext* ctx);
+    template <typename Context>
+    Status _prepare_and_open(Context* ctx);
 
-    std::string _get_result(void* src, PrimitiveType slot_type);
+    template <bool is_vec = false>
+    std::string _get_result(void* src, size_t size, PrimitiveType slot_type);
 
     std::unique_ptr<RuntimeState> _runtime_state;
     std::shared_ptr<MemTracker> _mem_tracker;
diff --git a/be/src/runtime/mysql_result_writer.cpp b/be/src/runtime/mysql_result_writer.cpp
index 1c2589c..eaf1bd7 100644
--- a/be/src/runtime/mysql_result_writer.cpp
+++ b/be/src/runtime/mysql_result_writer.cpp
@@ -29,6 +29,13 @@
 #include "util/mysql_row_buffer.h"
 #include "util/types.h"
 
+#include "vec/core/block.h"
+#include "vec/columns/column_vector.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/common/assert_cast.h"
+#include "vec/exprs/vexpr.h"
+#include "vec/exprs/vexpr_context.h"
+
 namespace doris {
 
 MysqlResultWriter::MysqlResultWriter(BufferControlBlock* sinker,
@@ -204,7 +211,6 @@ int MysqlResultWriter::_add_row_value(int index, const TypeDescriptor& type, voi
 }
 
 Status MysqlResultWriter::_add_one_row(TupleRow* row) {
-    SCOPED_TIMER(_convert_tuple_timer);
     _row_buffer->reset();
     int num_columns = _output_expr_ctxs.size();
     int buf_ret = 0;
diff --git a/be/src/runtime/mysql_result_writer.h b/be/src/runtime/mysql_result_writer.h
index 2754e0c..8b96fec 100644
--- a/be/src/runtime/mysql_result_writer.h
+++ b/be/src/runtime/mysql_result_writer.h
@@ -21,6 +21,8 @@
 #include "runtime/result_writer.h"
 #include "runtime/runtime_state.h"
 
+#include "vec/data_types/data_type.h"
+
 namespace doris {
 
 class TupleRow;
diff --git a/be/src/runtime/plan_fragment_executor.cpp b/be/src/runtime/plan_fragment_executor.cpp
index a464211..fe64a4f 100644
--- a/be/src/runtime/plan_fragment_executor.cpp
+++ b/be/src/runtime/plan_fragment_executor.cpp
@@ -42,6 +42,10 @@
 #include "util/uid_util.h"
 #include "util/logging.h"
 
+#include "vec/core/block.h"
+#include "vec/exec/vexchange_node.h"
+#include "vec/runtime/vdata_stream_mgr.h"
+
 namespace doris {
 
 PlanFragmentExecutor::PlanFragmentExecutor(ExecEnv* exec_env,
@@ -159,6 +163,7 @@ Status PlanFragmentExecutor::prepare(const TExecPlanFragmentParams& request,
         int num_senders = find_with_default(params.per_exch_num_senders, exch_node->id(), 0);
         DCHECK_GT(num_senders, 0);
         if (_runtime_state->enable_vectorized_exec()) {
+            static_cast<doris::vectorized::VExchangeNode*>(exch_node)->set_num_senders(num_senders);
         } else {
             static_cast<ExchangeNode*>(exch_node)->set_num_senders(num_senders);
         }
@@ -214,6 +219,7 @@ Status PlanFragmentExecutor::prepare(const TExecPlanFragmentParams& request,
 
     _row_batch.reset(new RowBatch(_plan->row_desc(), _runtime_state->batch_size(),
                                   _runtime_state->instance_mem_tracker().get()));
+    _block.reset(new doris::vectorized::Block());
     // _row_batch->tuple_data_pool()->set_limits(*_runtime_state->mem_trackers());
     VLOG_NOTICE << "plan_root=\n" << _plan->debug_string();
     _prepared = true;
@@ -244,6 +250,7 @@ Status PlanFragmentExecutor::open() {
     }
     Status status = Status::OK();
     if (_runtime_state->enable_vectorized_exec()) {
+        status = open_vectorized_internal();
     } else {
         status = open_internal();
     }
@@ -259,6 +266,82 @@ Status PlanFragmentExecutor::open() {
     return status;
 }
 
+Status PlanFragmentExecutor::open_vectorized_internal() {
+    {
+        SCOPED_CPU_TIMER(_fragment_cpu_timer);
+        SCOPED_TIMER(profile()->total_time_counter());
+        RETURN_IF_ERROR(_plan->open(_runtime_state.get()));
+    }
+    if (_sink == nullptr) {
+        return Status::OK();
+    }
+    {
+        SCOPED_CPU_TIMER(_fragment_cpu_timer);
+        RETURN_IF_ERROR(_sink->open(runtime_state()));
+    }
+    doris::vectorized::Block* block = nullptr;
+    while (true) {
+        {
+            SCOPED_CPU_TIMER(_fragment_cpu_timer);
+            RETURN_IF_ERROR(get_vectorized_internal(&block));
+        }
+
+        if (block == NULL) {
+            break;
+        } 
+
+        SCOPED_TIMER(profile()->total_time_counter());
+        SCOPED_CPU_TIMER(_fragment_cpu_timer);
+        // Collect this plan and sub plan statistics, and send to parent plan.
+        if (_collect_query_statistics_with_every_batch) {
+            _collect_query_statistics();
+        }
+        RETURN_IF_ERROR(_sink->send(runtime_state(), block));
+    }
+    {
+        SCOPED_TIMER(profile()->total_time_counter());
+        _collect_query_statistics();
+        Status status;
+        {
+            std::lock_guard<std::mutex> l(_status_lock);
+            status = _status;
+        }
+        status = _sink->close(runtime_state(), status);
+        RETURN_IF_ERROR(status);
+    }
+    // Setting to NULL ensures that the d'tor won't double-close the sink.
+    _sink.reset(nullptr);
+    _done = true;
+
+    stop_report_thread();
+    send_report(true);
+
+    return Status::OK();
+}
+Status PlanFragmentExecutor::get_vectorized_internal(::doris::vectorized::Block** block) {
+    if (_done) {
+        *block = nullptr;
+        return Status::OK();
+    }
+
+    auto vexec_node = static_cast<doris::ExecNode*>(_plan);
+    while (!_done) {
+        _block->clear_column_data(vexec_node->row_desc().num_materialized_slots());
+        SCOPED_TIMER(profile()->total_time_counter());
+        RETURN_IF_ERROR(vexec_node->get_next(_runtime_state.get(), _block.get(), &_done));
+
+        if (_block->rows() > 0) {
+            COUNTER_UPDATE(_rows_produced_counter, _block->rows());
+            *block = _block.get();
+            break;
+        }
+
+        *block = nullptr;
+    }
+
+    return Status::OK();
+}
+
 Status PlanFragmentExecutor::open_internal() {
     {
         SCOPED_CPU_TIMER(_fragment_cpu_timer);
@@ -521,8 +604,14 @@ void PlanFragmentExecutor::cancel() {
                   .query_id(_query_id).instance_id(_runtime_state->fragment_instance_id());
     DCHECK(_prepared);
     _runtime_state->set_is_cancelled(true);
-    _runtime_state->exec_env()->stream_mgr()->cancel(_runtime_state->fragment_instance_id());
-    _runtime_state->exec_env()->result_mgr()->cancel(_runtime_state->fragment_instance_id());
+
+    // must close stream_mgr to avoid dead lock in Exchange Node
+    if (_runtime_state->enable_vectorized_exec()) {
+        _runtime_state->exec_env()->vstream_mgr()->cancel(_runtime_state->fragment_instance_id());
+    } else {
+        _runtime_state->exec_env()->stream_mgr()->cancel(_runtime_state->fragment_instance_id());
+        _runtime_state->exec_env()->result_mgr()->cancel(_runtime_state->fragment_instance_id());
+    }
 }
 
 void PlanFragmentExecutor::set_abort() {
diff --git a/be/src/runtime/plan_fragment_executor.h b/be/src/runtime/plan_fragment_executor.h
index 1fc4578..3cdb6bb 100644
--- a/be/src/runtime/plan_fragment_executor.h
+++ b/be/src/runtime/plan_fragment_executor.h
@@ -30,11 +30,11 @@
 #include "runtime/runtime_state.h"
 #include "util/hash_util.hpp"
 #include "util/time.h"
+#include "vec/core/block.h"
 
 namespace doris {
 
 class QueryFragmentsCtx;
-class HdfsFsCache;
 class ExecNode;
 class RowDescriptor;
 class RowBatch;
@@ -195,6 +195,7 @@ private:
     // Created in prepare (if required), owned by this object.
     std::unique_ptr<DataSink> _sink;
     std::unique_ptr<RowBatch> _row_batch;
+    std::unique_ptr<doris::vectorized::Block> _block;
 
     // Number of rows returned by this fragment
     RuntimeProfile::Counter* _rows_produced_counter;
@@ -234,9 +235,11 @@ private:
     // have been closed, a final report will have been sent and the report thread will
     // have been stopped. _sink will be set to nullptr after successful execution.
     Status open_internal();
+    Status open_vectorized_internal();
 
     // Executes get_next() logic and returns resulting status.
     Status get_next_internal(RowBatch** batch);
+    Status get_vectorized_internal(::doris::vectorized::Block** block);
 
     // Stops report thread, if one is running. Blocks until report thread terminates.
     // Idempotent.
diff --git a/be/src/runtime/primitive_type.h b/be/src/runtime/primitive_type.h
index 36113a5..224957f 100644
--- a/be/src/runtime/primitive_type.h
+++ b/be/src/runtime/primitive_type.h
@@ -27,6 +27,13 @@
 #include "runtime/decimalv2_value.h"
 #include "runtime/large_int_value.h"
 #include "runtime/string_value.h"
+#include "udf/udf.h"
+
+#include "vec/columns/column_decimal.h"
+#include "vec/columns/column_string.h"
+#include "vec/columns/columns_number.h"
+#include "vec/core/types.h"
+#include "vec/runtime/vdatetime_value.h"
 
 namespace doris {
 
@@ -60,6 +67,51 @@ enum PrimitiveType {
     TYPE_STRING, /* 23 */
 };
 
+inline PrimitiveType convert_type_to_primitive(FunctionContext::Type type) {
+    switch (type) {
+    case FunctionContext::Type::INVALID_TYPE:
+        return PrimitiveType::INVALID_TYPE;
+    case FunctionContext::Type::TYPE_DOUBLE:
+        return PrimitiveType::TYPE_DOUBLE;
+    case FunctionContext::Type::TYPE_NULL:
+        return PrimitiveType::TYPE_NULL;
+    case FunctionContext::Type::TYPE_CHAR:
+        return PrimitiveType::TYPE_CHAR;
+    case FunctionContext::Type::TYPE_VARCHAR:
+        return PrimitiveType::TYPE_VARCHAR;
+    case FunctionContext::Type::TYPE_STRING:
+        return PrimitiveType::TYPE_STRING;
+    case FunctionContext::Type::TYPE_DATETIME:
+        return PrimitiveType::TYPE_DATETIME;
+    case FunctionContext::Type::TYPE_DECIMALV2:
+        return PrimitiveType::TYPE_DECIMALV2;
+    case FunctionContext::Type::TYPE_BOOLEAN:
+        return PrimitiveType::TYPE_BOOLEAN;
+    case FunctionContext::Type::TYPE_ARRAY:
+        return PrimitiveType::TYPE_ARRAY;
+    case FunctionContext::Type::TYPE_OBJECT:
+        return PrimitiveType::TYPE_OBJECT;
+    case FunctionContext::Type::TYPE_HLL:
+        return PrimitiveType::TYPE_HLL;
+    case FunctionContext::Type::TYPE_TINYINT:
+        return PrimitiveType::TYPE_TINYINT;
+    case FunctionContext::Type::TYPE_SMALLINT:
+        return PrimitiveType::TYPE_SMALLINT;
+    case FunctionContext::Type::TYPE_INT:
+        return PrimitiveType::TYPE_INT;
+    case FunctionContext::Type::TYPE_BIGINT:
+        return PrimitiveType::TYPE_BIGINT;
+    case FunctionContext::Type::TYPE_LARGEINT:
+        return PrimitiveType::TYPE_LARGEINT;
+    case FunctionContext::Type::TYPE_DATE:
+        return PrimitiveType::TYPE_DATE;
+    default:
+        DCHECK(false);
+    }
+
+    return PrimitiveType::INVALID_TYPE;
+}
+
 inline bool is_enumeration_type(PrimitiveType type) {
     switch (type) {
     case TYPE_FLOAT:
@@ -98,6 +150,10 @@ inline bool is_string_type(PrimitiveType type) {
     return type == TYPE_CHAR || type == TYPE_VARCHAR || type == TYPE_STRING;
 }
 
+inline bool has_variable_type(PrimitiveType type) {
+    return type == TYPE_CHAR || type == TYPE_VARCHAR || type == TYPE_OBJECT || type == TYPE_STRING;
+}
+
 // Returns the byte size of 'type'  Returns 0 for variable length types.
 inline int get_byte_size(PrimitiveType type) {
     switch (type) {
@@ -125,9 +181,9 @@ inline int get_byte_size(PrimitiveType type) {
     case TYPE_DOUBLE:
         return 8;
 
-    case TYPE_LARGEINT:
     case TYPE_DATETIME:
     case TYPE_DATE:
+    case TYPE_LARGEINT:
     case TYPE_DECIMALV2:
         return 16;
 
@@ -220,63 +276,78 @@ struct PrimitiveTypeTraits {};
 template <>
 struct PrimitiveTypeTraits<TYPE_BOOLEAN> {
     using CppType = bool;
+    using ColumnType = vectorized::ColumnUInt8;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_TINYINT> {
     using CppType = int8_t;
+    using ColumnType = vectorized::ColumnInt8;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_SMALLINT> {
     using CppType = int16_t;
+    using ColumnType = vectorized::ColumnInt16;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_INT> {
     using CppType = int32_t;
+    using ColumnType = vectorized::ColumnInt32;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_BIGINT> {
     using CppType = int64_t;
+    using ColumnType = vectorized::ColumnInt64;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_FLOAT> {
     using CppType = float;
+    using ColumnType = vectorized::ColumnFloat32;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_TIME> {
     using CppType = double;
+    using ColumnType = vectorized::ColumnFloat64;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_DOUBLE> {
     using CppType = double;
+    using ColumnType = vectorized::ColumnFloat64;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_DATE> {
-    using CppType = DateTimeValue;
+    using CppType = doris::DateTimeValue;
+    using ColumnType = vectorized::ColumnVector<vectorized::DateTime>;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_DATETIME> {
-    using CppType = DateTimeValue;
+    using CppType = doris::DateTimeValue;
+    using ColumnType = vectorized::ColumnVector<vectorized::DateTime>;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_DECIMALV2> {
     using CppType = DecimalV2Value;
+    using ColumnType = vectorized::ColumnDecimal<vectorized::Decimal128>;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_LARGEINT> {
     using CppType = __int128_t;
+    using ColumnType = vectorized::ColumnInt128;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_CHAR> {
     using CppType = StringValue;
+    using ColumnType = vectorized::ColumnString;
 };
 template <>
 struct PrimitiveTypeTraits<TYPE_VARCHAR> {
     using CppType = StringValue;
+    using ColumnType = vectorized::ColumnString;
 };
 
 template <>
 struct PrimitiveTypeTraits<TYPE_STRING> {
     using CppType = StringValue;
+    using ColumnType = vectorized::ColumnString;
 };
 
 } // namespace doris
diff --git a/be/src/runtime/raw_value.h b/be/src/runtime/raw_value.h
index e9e270e..e16bbf5 100644
--- a/be/src/runtime/raw_value.h
+++ b/be/src/runtime/raw_value.h
@@ -87,6 +87,9 @@ public:
     // TODO: fix get_hash_value
     static uint32_t zlib_crc32(const void* value, const TypeDescriptor& type, uint32_t seed);
 
+    // Same as the up function, only use in vec exec engine.
+    static uint32_t zlib_crc32(const void* value, size_t len, const TypeDescriptor& type, uint32_t seed);
+
     // Compares both values.
     // Return value is < 0  if v1 < v2, 0 if v1 == v2, > 0 if v1 > v2.
     static int compare(const void* v1, const void* v2, const TypeDescriptor& type);
@@ -399,6 +402,59 @@ inline uint32_t RawValue::zlib_crc32(const void* v, const TypeDescriptor& type,
     }
 }
 
+// NOTE: this is just for split data, decimal use old doris hash function
+// Because crc32 hardware is not equal with zlib crc32
+inline uint32_t RawValue::zlib_crc32(const void* v, size_t len, const TypeDescriptor& type, uint32_t seed) {
+    // Hash_combine with v = 0
+    if (v == nullptr) {
+        uint32_t value = 0x9e3779b9;
+        return seed ^ (value + (seed << 6) + (seed >> 2));
+    }
+
+    switch (type.type) {
+    case TYPE_VARCHAR:
+    case TYPE_HLL:
+    case TYPE_STRING:
+    case TYPE_CHAR: {
+        return HashUtil::zlib_crc_hash(v, len, seed);
+    }
+
+    case TYPE_BOOLEAN:
+    case TYPE_TINYINT:
+        return HashUtil::zlib_crc_hash(v, 1, seed);
+    case TYPE_SMALLINT:
+        return HashUtil::zlib_crc_hash(v, 2, seed);
+    case TYPE_INT:
+        return HashUtil::zlib_crc_hash(v, 4, seed);
+    case TYPE_BIGINT:
+        return HashUtil::zlib_crc_hash(v, 8, seed);
+    case TYPE_LARGEINT:
+        return HashUtil::zlib_crc_hash(v, 16, seed);
+    case TYPE_FLOAT:
+        return HashUtil::zlib_crc_hash(v, 4, seed);
+    case TYPE_DOUBLE:
+        return HashUtil::zlib_crc_hash(v, 8, seed);
+    case TYPE_DATE:
+    case TYPE_DATETIME: {
+        auto* date_val = (const vectorized::VecDateTimeValue*)v;
+        char buf[64];
+        int len = date_val->to_buffer(buf);
+        return HashUtil::zlib_crc_hash(buf, len, seed);
+    }
+
+    case TYPE_DECIMALV2: {
+        const DecimalV2Value* dec_val = (const DecimalV2Value*)v;
+        int64_t int_val = dec_val->int_value();
+        int32_t frac_val = dec_val->frac_value();
+        seed = HashUtil::zlib_crc_hash(&int_val, sizeof(int_val), seed);
+        return HashUtil::zlib_crc_hash(&frac_val, sizeof(frac_val), seed);
+    }
+    default:
+        DCHECK(false) << "invalid type: " << type;
+        return 0;
+    }
+}
+
 } // namespace doris
 
 #endif
diff --git a/be/src/runtime/result_sink.cpp b/be/src/runtime/result_sink.cpp
index 206b0f0..60538ca 100644
--- a/be/src/runtime/result_sink.cpp
+++ b/be/src/runtime/result_sink.cpp
@@ -29,6 +29,8 @@
 #include "runtime/runtime_state.h"
 #include "util/uid_util.h"
 
+#include "vec/exprs/vexpr.h"
+
 namespace doris {
 
 ResultSink::ResultSink(const RowDescriptor& row_desc, const std::vector<TExpr>& t_output_expr,
diff --git a/be/src/runtime/row_batch.cpp b/be/src/runtime/row_batch.cpp
index 85ba3c7..3e7914e 100644
--- a/be/src/runtime/row_batch.cpp
+++ b/be/src/runtime/row_batch.cpp
@@ -30,8 +30,8 @@
 #include "runtime/string_value.h"
 #include "runtime/tuple_row.h"
 
-//#include "vec/columns/column_vector.h"
-//#include "vec/core/block.h"
+#include "vec/columns/column_vector.h"
+#include "vec/core/block.h"
 
 using std::vector;
 
@@ -625,6 +625,57 @@ void RowBatch::transfer_resource_ownership(RowBatch* dest) {
     reset();
 }
 
+vectorized::Block RowBatch::convert_to_vec_block() const {
+    std::vector<vectorized::MutableColumnPtr> columns;
+    for (const auto tuple_desc : _row_desc.tuple_descriptors()) {
+        for (const auto slot_desc : tuple_desc->slots()) {
+            columns.emplace_back(slot_desc->get_empty_mutable_column());
+        }
+    }
+
+    std::vector<SlotDescriptor*> slot_descs;
+    std::vector<int> tuple_idx;
+    int column_numbers = 0;
+    for (int i = 0; i < _row_desc.tuple_descriptors().size(); ++i) {
+        auto tuple_desc = _row_desc.tuple_descriptors()[i];
+        for (int j = 0; j < tuple_desc->slots().size(); ++j) {
+            slot_descs.push_back(tuple_desc->slots()[j]);
+            tuple_idx.push_back(i);
+        }
+        column_numbers += tuple_desc->slots().size();
+    }
+    for (int i = 0; i < column_numbers; ++i) {
+        auto slot_desc = slot_descs[i];
+        for (int j = 0; j < _num_rows; ++j) {
+            TupleRow* src_row = get_row(j);
+            auto tuple = src_row->get_tuple(tuple_idx[i]);
+            if (slot_desc->is_nullable() && tuple->is_null(slot_desc->null_indicator_offset())) {
+                columns[i]->insert_data(nullptr, 0);
+            } else if (slot_desc->type().is_string_type()) {
+                auto string_value =
+                        static_cast<const StringValue*>(tuple->get_slot(slot_desc->tuple_offset()));
+                columns[i]->insert_data(string_value->ptr, string_value->len);
+            } else {
+                columns[i]->insert_data(
+                        static_cast<const char*>(tuple->get_slot(slot_desc->tuple_offset())),
+                        slot_desc->slot_size());
+            }
+        }
+    }
+
+    doris::vectorized::ColumnsWithTypeAndName columns_with_type_and_name;
+    auto n_columns = 0;
+    for (const auto tuple_desc : _row_desc.tuple_descriptors()) {
+        for (const auto slot_desc : tuple_desc->slots()) {
+            columns_with_type_and_name.emplace_back(columns[n_columns++]->get_ptr(),
+                                                    slot_desc->get_data_type_ptr(),
+                                                    slot_desc->col_name());
+        }
+    }
+
+    return {columns_with_type_and_name};
+}
+
 size_t RowBatch::get_batch_size(const TRowBatch& batch) {
     size_t result = batch.tuple_data.size();
     result += batch.row_tuples.size() * sizeof(TTupleId);
@@ -688,6 +739,7 @@ void RowBatch::deep_copy_to(RowBatch* dst) {
     }
     dst->commit_rows(_num_rows);
 }
+
 // TODO: consider computing size of batches as they are built up
 size_t RowBatch::total_byte_size() const {
     size_t result = 0;
diff --git a/be/src/runtime/row_batch.h b/be/src/runtime/row_batch.h
index 596fa70..4333c73 100644
--- a/be/src/runtime/row_batch.h
+++ b/be/src/runtime/row_batch.h
@@ -43,6 +43,7 @@ class TupleRow;
 class TupleDescriptor;
 class PRowBatch;
 
+
 // A RowBatch encapsulates a batch of rows, each composed of a number of tuples.
 // The maximum number of rows is fixed at the time of construction, and the caller
 // can add rows up to that capacity.
@@ -315,7 +316,7 @@ public:
     // we firstly update dest resource, and then reset current resource
     void transfer_resource_ownership(RowBatch* dest);
 
-    void copy_row(const TupleRow* src, TupleRow* dest) const {
+    void copy_row(TupleRow* src, TupleRow* dest) {
         memcpy(dest, src, _num_tuples_per_row * sizeof(Tuple*));
     }
 
@@ -362,6 +363,8 @@ public:
     static size_t get_batch_size(const TRowBatch& batch);
     static size_t get_batch_size(const PRowBatch& batch);
 
+    vectorized::Block convert_to_vec_block() const;
+
     int num_rows() const { return _num_rows; }
     int capacity() const { return _capacity; }
 
diff --git a/be/src/runtime/string_value.hpp b/be/src/runtime/string_value.hpp
index dd29bff..c44115d 100644
--- a/be/src/runtime/string_value.hpp
+++ b/be/src/runtime/string_value.hpp
@@ -42,22 +42,19 @@ static inline int string_compare(const char* s1, int64_t n1, const char* s2, int
                                  int64_t len) {
     DCHECK_EQ(len, std::min(n1, n2));
 #ifdef __SSE4_2__
-    if (CpuInfo::is_supported(CpuInfo::SSE4_2)) {
-        while (len >= sse_util::CHARS_PER_128_BIT_REGISTER) {
-            __m128i xmm0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s1));
-            __m128i xmm1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s2));
-            int chars_match =
-                    _mm_cmpestri(xmm0, sse_util::CHARS_PER_128_BIT_REGISTER, xmm1,
-                                 sse_util::CHARS_PER_128_BIT_REGISTER, sse_util::STRCMP_MODE);
-            if (chars_match != sse_util::CHARS_PER_128_BIT_REGISTER) {
-                return (unsigned char)s1[chars_match] - (unsigned char)s2[chars_match];
-            }
-            len -= sse_util::CHARS_PER_128_BIT_REGISTER;
-            s1 += sse_util::CHARS_PER_128_BIT_REGISTER;
-            s2 += sse_util::CHARS_PER_128_BIT_REGISTER;
+    while (len >= sse_util::CHARS_PER_128_BIT_REGISTER) {
+        __m128i xmm0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s1));
+        __m128i xmm1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s2));
+        int chars_match =
+                _mm_cmpestri(xmm0, sse_util::CHARS_PER_128_BIT_REGISTER, xmm1,
+                             sse_util::CHARS_PER_128_BIT_REGISTER, sse_util::STRCMP_MODE);
+        if (chars_match != sse_util::CHARS_PER_128_BIT_REGISTER) {
+            return (unsigned char)s1[chars_match] - (unsigned char)s2[chars_match];
         }
+        len -= sse_util::CHARS_PER_128_BIT_REGISTER;
+        s1 += sse_util::CHARS_PER_128_BIT_REGISTER;
+        s2 += sse_util::CHARS_PER_128_BIT_REGISTER;
     }
-
 #endif
     unsigned char u1, u2;
     while (len-- > 0) {
diff --git a/be/src/runtime/types.h b/be/src/runtime/types.h
index e40bc5b..c2adca9 100644
--- a/be/src/runtime/types.h
+++ b/be/src/runtime/types.h
@@ -28,6 +28,12 @@
 #include "runtime/collection_value.h"
 #include "runtime/primitive_type.h"
 #include "thrift/protocol/TDebugProtocol.h"
+#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_decimal.h"
+#include "vec/data_types/data_type_number.h"
+#include "vec/data_types/data_type_string.h"
 
 namespace doris {
 
@@ -272,6 +278,58 @@ struct TypeDescriptor {
         return -1;
     }
 
+    inline doris::vectorized::DataTypePtr get_data_type_ptr() const {
+        switch (type) {
+        case TYPE_BOOLEAN:
+            return std::make_shared<vectorized::DataTypeUInt8>();
+
+        case TYPE_TINYINT:
+            return std::make_shared<vectorized::DataTypeInt8>();
+
+        case TYPE_SMALLINT:
+            return std::make_shared<vectorized::DataTypeInt16>();
+
+        case TYPE_INT:
+            return std::make_shared<vectorized::DataTypeInt32>();
+
+        case TYPE_FLOAT:
+            return std::make_shared<vectorized::DataTypeFloat32>();
+
+        case TYPE_BIGINT:
+            return std::make_shared<vectorized::DataTypeInt64>();
+
+        case TYPE_LARGEINT:
+            return std::make_shared<vectorized::DataTypeInt128>();
+        case TYPE_DATE:
+            return std::make_shared<vectorized::DataTypeDate>();
+        case TYPE_DATETIME:
+            return std::make_shared<vectorized::DataTypeDateTime>();
+        case TYPE_TIME:
+        case TYPE_DOUBLE:
+            return std::make_shared<vectorized::DataTypeFloat64>();
+
+        case TYPE_STRING:
+        case TYPE_CHAR:
+        case TYPE_VARCHAR:
+        case TYPE_HLL:
+            return std::make_shared<vectorized::DataTypeString>();
+        case TYPE_OBJECT:
+            return std::make_shared<vectorized::DataTypeBitMap>();
+
+        case TYPE_DECIMALV2:
+            return std::make_shared<vectorized::DataTypeDecimal<vectorized::Decimal128>>(27, 9);
+        // Just Mock A NULL Type in Vec Exec Engine
+        case TYPE_NULL:
+            return std::make_shared<vectorized::DataTypeUInt8>();
+
+        case INVALID_TYPE:
+        default:
+            DCHECK(false);
+        }
+        // For llvm complain
+        return nullptr;
+    }
+
     static inline int get_decimal_byte_size(int precision) {
         DCHECK_GT(precision, 0);
         if (precision <= MAX_DECIMAL4_PRECISION) {
diff --git a/be/src/service/internal_service.cpp b/be/src/service/internal_service.cpp
index ee6cf7e..4106963 100644
--- a/be/src/service/internal_service.cpp
+++ b/be/src/service/internal_service.cpp
@@ -36,6 +36,7 @@
 #include "util/string_util.h"
 #include "util/thrift_util.h"
 #include "util/uid_util.h"
+#include "vec/runtime/vdata_stream_mgr.h"
 
 namespace doris {
 
@@ -422,7 +423,10 @@ Status PInternalServiceImpl<T>::_fold_constant_expr(const std::string& ser_reque
         uint32_t len = ser_request.size();
         RETURN_IF_ERROR(deserialize_thrift_msg(buf, &len, false, &t_request));
     }
-    return FoldConstantExecutor().fold_constant_expr(t_request, response);
+    if (!t_request.__isset.vec_exec || !t_request.vec_exec)
+        return FoldConstantExecutor().fold_constant_expr(t_request, response);
+
+    return FoldConstantExecutor().fold_constant_vexpr(t_request, response);
 }
 
 template <typename T>
@@ -432,6 +436,7 @@ void PInternalServiceImpl<T>::transmit_block(google::protobuf::RpcController* cn
                                              google::protobuf::Closure* done) {
     VLOG_ROW << "transmit data: fragment_instance_id=" << print_id(request->finst_id())
              << " node=" << request->node_id();
+    _exec_env->vstream_mgr()->transmit_block(request, &done);
     if (done != nullptr) {
         done->Run();
     }
diff --git a/be/src/udf/udf.cpp b/be/src/udf/udf.cpp
index 0360f39..269bd88 100644
--- a/be/src/udf/udf.cpp
+++ b/be/src/udf/udf.cpp
@@ -131,6 +131,10 @@ void FunctionContextImpl::set_constant_args(const std::vector<doris_udf::AnyVal*
     _constant_args = constant_args;
 }
 
+void FunctionContextImpl::set_constant_cols(const std::vector<doris::ColumnPtrWrapper*>& constant_cols) {
+    _constant_cols = constant_cols;
+}
+
 bool FunctionContextImpl::check_allocations_empty() {
     if (_allocations.empty() && _external_bytes_tracked == 0) {
         return true;
@@ -187,6 +191,7 @@ FunctionContext* FunctionContextImpl::clone(MemPool* pool) {
             create_context(_state, pool, _intermediate_type, _return_type, _arg_types,
                            _varargs_buffer_size, _debug);
     new_context->_impl->_constant_args = _constant_args;
+    new_context->_impl->_constant_cols = _constant_cols;
     new_context->_impl->_fragment_local_fn_state = _fragment_local_fn_state;
     return new_context;
 }
diff --git a/be/src/udf/udf.h b/be/src/udf/udf.h
index 3b9ff5a..141219a 100644
--- a/be/src/udf/udf.h
+++ b/be/src/udf/udf.h
@@ -28,6 +28,7 @@
 // object serves as the interface object between the UDF/UDA and the doris process.
 namespace doris {
 class FunctionContextImpl;
+class ColumnPtrWrapper;
 struct StringValue;
 struct BitmapValue;
 struct DecimalV2Value;
@@ -224,12 +225,16 @@ public:
     // FunctionContext* argument) is a constant (e.g. 5, "string", 1 + 1).
     bool is_arg_constant(int arg_idx) const;
 
+    bool is_col_constant(int arg_idx) const;
+
     // Returns a pointer to the value of the arg_idx-th input argument (0 indexed, not
     // including the FunctionContext* argument). Returns nullptr if the argument is not
     // constant. This function can be used to obtain user-specified constants in a UDF's
     // Init() or Close() functions.
     AnyVal* get_constant_arg(int arg_idx) const;
 
+    doris::ColumnPtrWrapper* get_constant_col(int arg_idx) const;
+
     // Create a test FunctionContext object. The caller is responsible for calling delete
     // on it. This context has additional debugging validation enabled.
     static FunctionContext* create_test_context();
diff --git a/be/src/udf/udf_internal.h b/be/src/udf/udf_internal.h
index 2d2c318..085002d 100644
--- a/be/src/udf/udf_internal.h
+++ b/be/src/udf/udf_internal.h
@@ -32,6 +32,7 @@ namespace doris {
 class FreePool;
 class MemPool;
 class RuntimeState;
+class ColumnPtrWrapper;
 
 // This class actually implements the interface of FunctionContext. This is split to
 // hide the details from the external header.
@@ -67,6 +68,8 @@ public:
 
     void set_constant_args(const std::vector<doris_udf::AnyVal*>& constant_args);
 
+    void set_constant_cols(const std::vector<doris::ColumnPtrWrapper*>& cols);
+
     uint8_t* varargs_buffer() { return _varargs_buffer; }
 
     std::vector<doris_udf::AnyVal*>* staging_input_vals() { return &_staging_input_vals; }
@@ -169,6 +172,8 @@ private:
     // value of the argument.
     std::vector<doris_udf::AnyVal*> _constant_args;
 
+    std::vector<doris::ColumnPtrWrapper*> _constant_cols;
+
     // Used by ScalarFnCall to store the arguments when running without codegen. Allows us
     // to pass AnyVal* arguments to the scalar function directly, rather than codegening a
     // call that passes the correct AnyVal subclass pointer type.
diff --git a/be/src/udf/udf_ir.cpp b/be/src/udf/udf_ir.cpp
index 4eefd17..a1ceb02 100644
--- a/be/src/udf/udf_ir.cpp
+++ b/be/src/udf/udf_ir.cpp
@@ -25,6 +25,13 @@ bool FunctionContext::is_arg_constant(int i) const {
     return _impl->_constant_args[i] != nullptr;
 }
 
+bool FunctionContext::is_col_constant(int i) const {
+    if (i < 0 || i >= _impl->_constant_cols.size()) {
+        return false;
+    }
+    return _impl->_constant_cols[i] != nullptr;
+}
+
 AnyVal* FunctionContext::get_constant_arg(int i) const {
     if (i < 0 || i >= _impl->_constant_args.size()) {
         return nullptr;
@@ -32,6 +39,13 @@ AnyVal* FunctionContext::get_constant_arg(int i) const {
     return _impl->_constant_args[i];
 }
 
+doris::ColumnPtrWrapper* FunctionContext::get_constant_col(int i) const {
+    if (i < 0 || i >= _impl->_constant_cols.size()) {
+        return nullptr;
+    }
+    return _impl->_constant_cols[i];
+}
+
 int FunctionContext::get_num_args() const {
     return _impl->_arg_types.size();
 }
diff --git a/be/src/util/binary_cast.hpp b/be/src/util/binary_cast.hpp
index d528d71..764f5b5 100644
--- a/be/src/util/binary_cast.hpp
+++ b/be/src/util/binary_cast.hpp
@@ -23,7 +23,7 @@
 #include "runtime/datetime_value.h"
 #include "runtime/decimalv2_value.h"
 #include "util/types.h"
-
+#include "vec/runtime/vdatetime_value.h"
 namespace doris {
 union TypeConverter {
     uint64_t u64;
@@ -56,6 +56,11 @@ union DateTimeInt128Union {
     ~DateTimeInt128Union() {}
 };
 
+union VecDateTimeInt64Union {
+    doris::vectorized::VecDateTimeValue dt;
+    __int64_t i64;
+    ~VecDateTimeInt64Union() {}
+};
 // similar to reinterpret_cast but won't break strict-aliasing rules
 template <typename From, typename To>
 To binary_cast(From from) {
@@ -66,11 +71,13 @@ To binary_cast(From from) {
     constexpr bool from_decv2_to_packed128 = match_v<From, DecimalV2Value, To, PackedInt128>;
     constexpr bool from_i128_to_dt = match_v<From, __int128_t, To, DateTimeValue>;
     constexpr bool from_dt_to_i128 = match_v<From, DateTimeValue, To, __int128_t>;
+    constexpr bool from_i64_to_vec_dt = match_v<From, __int64_t, To, doris::vectorized::VecDateTimeValue>;
+    constexpr bool from_vec_dt_to_i64 = match_v<From, doris::vectorized::VecDateTimeValue, To, __int64_t>;
     constexpr bool from_i128_to_decv2 = match_v<From, __int128_t, To, DecimalV2Value>;
     constexpr bool from_decv2_to_i128 = match_v<From, DecimalV2Value, To, __int128_t>;
 
     static_assert(from_u64_to_db || from_i64_to_db || from_db_to_i64 || from_db_to_u64 ||
-                  from_decv2_to_packed128 || from_i128_to_dt || from_dt_to_i128 ||
+                  from_decv2_to_packed128 || from_i128_to_dt || from_dt_to_i128 || from_i64_to_vec_dt || from_vec_dt_to_i64 ||
                   from_i128_to_decv2 || from_decv2_to_i128);
 
     if constexpr (from_u64_to_db) {
@@ -99,6 +106,12 @@ To binary_cast(From from) {
     } else if constexpr (from_dt_to_i128) {
         DateTimeInt128Union conv = {.dt = from};
         return conv.i128;
+    } else if constexpr (from_i64_to_vec_dt) {
+        VecDateTimeInt64Union conv = {.i64 = from};
+        return conv.dt;
+    } else if constexpr (from_vec_dt_to_i64) {
+        VecDateTimeInt64Union conv = {.dt = from};
+        return conv.i64;
     } else if constexpr (from_i128_to_decv2) {
         DecimalInt128Union conv;
         conv.i128 = from;
diff --git a/be/src/util/bitmap_value.h b/be/src/util/bitmap_value.h
index 81fb10b..bdb124b 100644
--- a/be/src/util/bitmap_value.h
+++ b/be/src/util/bitmap_value.h
@@ -1691,6 +1691,12 @@ public:
         }
         return count;
     }
+    
+    void clear() {
+        _type = EMPTY;
+        _bitmap.clear();
+        _sv = 0;
+    }
 
     // Implement an iterator for convenience
     friend class BitmapValueIterator;
diff --git a/be/src/util/brpc_stub_cache.h b/be/src/util/brpc_stub_cache.h
index 53ee3b7..21800f3 100644
--- a/be/src/util/brpc_stub_cache.h
+++ b/be/src/util/brpc_stub_cache.h
@@ -47,7 +47,7 @@ namespace doris {
 class BrpcStubCache {
 public:
     BrpcStubCache();
-    ~BrpcStubCache();
+    virtual ~BrpcStubCache();
 
     inline std::shared_ptr<PBackendService_Stub> get_stub(const butil::EndPoint& endpoint) {
         auto stub_ptr = _stub_map.find(endpoint);
@@ -66,7 +66,7 @@ public:
         return stub;
     }
 
-    inline std::shared_ptr<PBackendService_Stub> get_stub(const TNetworkAddress& taddr) {
+    virtual std::shared_ptr<PBackendService_Stub> get_stub(const TNetworkAddress& taddr) {
         butil::EndPoint endpoint;
         if (str2endpoint(taddr.hostname.c_str(), taddr.port, &endpoint)) {
             LOG(WARNING) << "unknown endpoint, hostname=" << taddr.hostname
diff --git a/be/src/util/runtime_profile.h b/be/src/util/runtime_profile.h
index f2632d5..1e9366f 100644
--- a/be/src/util/runtime_profile.h
+++ b/be/src/util/runtime_profile.h
@@ -52,8 +52,9 @@ namespace doris {
     ScopedTimer<ThreadCpuStopWatch> MACRO_CONCAT(SCOPED_TIMER, __COUNTER__)(c)
 #define CANCEL_SAFE_SCOPED_TIMER(c, is_cancelled) \
     ScopedTimer<MonotonicStopWatch> MACRO_CONCAT(SCOPED_TIMER, __COUNTER__)(c, is_cancelled)
-#define SCOPED_RAW_TIMER(c) \
-    ScopedRawTimer<MonotonicStopWatch, int64_t> MACRO_CONCAT(SCOPED_RAW_TIMER, __COUNTER__)(c)
+#define SCOPED_RAW_TIMER(c)                                                                  \
+    doris::ScopedRawTimer<doris::MonotonicStopWatch, int64_t> MACRO_CONCAT(SCOPED_RAW_TIMER, \
+                                                                           __COUNTER__)(c)
 #define SCOPED_ATOMIC_TIMER(c)                                                                 \
     ScopedRawTimer<MonotonicStopWatch, std::atomic<int64_t>> MACRO_CONCAT(SCOPED_ATOMIC_TIMER, \
                                                                           __COUNTER__)(c)
diff --git a/be/src/util/static_asserts.cpp b/be/src/util/static_asserts.cpp
index eb50636..43833ad 100644
--- a/be/src/util/static_asserts.cpp
+++ b/be/src/util/static_asserts.cpp
@@ -17,7 +17,7 @@
 
 #include "runtime/datetime_value.h"
 #include "runtime/string_value.h"
-
+#include "vec/runtime/vdatetime_value.h"
 namespace doris {
 // This class is unused.  It contains static (compile time) asserts.
 // This is useful to validate struct sizes and other similar things
@@ -28,6 +28,7 @@ private:
     static_assert(offsetof(StringValue, len) == 8);
     // Datetime value
     static_assert(sizeof(DateTimeValue) == 16);
+    static_assert(sizeof(doris::vectorized::VecDateTimeValue) == 8);
     // static_assert(offsetof(DateTimeValue, _year) == 8);
 };
 
diff --git a/be/src/util/string_parser.hpp b/be/src/util/string_parser.hpp
index 0354343..cc1110c 100644
--- a/be/src/util/string_parser.hpp
+++ b/be/src/util/string_parser.hpp
@@ -573,6 +573,26 @@ T StringParser::numeric_limits(bool negative) {
 }
 
 template<>
+inline int StringParser::StringParseTraits<uint8_t>::max_ascii_len() {
+    return 3;
+}
+
+template<>
+inline int StringParser::StringParseTraits<uint16_t>::max_ascii_len() {
+    return 5;
+}
+
+template<>
+inline int StringParser::StringParseTraits<uint32_t>::max_ascii_len() {
+    return 10;
+}
+
+template<>
+inline int StringParser::StringParseTraits<uint64_t>::max_ascii_len() {
+    return 20;
+}
+
+template<>
 inline int StringParser::StringParseTraits<int8_t>::max_ascii_len() {
     return 3;
 }
diff --git a/be/src/util/url_coding.cpp b/be/src/util/url_coding.cpp
index 862c34cc..3c41114 100644
--- a/be/src/util/url_coding.cpp
+++ b/be/src/util/url_coding.cpp
@@ -194,6 +194,10 @@ int64_t base64_decode(const char* data, size_t length, char* decoded_data) {
 
     // run through the whole string, converting as we go
     while ((ch = *current++) != '\0' && length-- > 0) {
+        if (ch >= 256 || ch < 0) {
+            return -1;
+        }
+
         if (ch == base64_pad) {
             if (*current != '=' && (i % 4) == 1) {
                 return -1;
diff --git a/be/src/vec/CMakeLists.txt b/be/src/vec/CMakeLists.txt
new file mode 100644
index 0000000..f737391
--- /dev/null
+++ b/be/src/vec/CMakeLists.txt
@@ -0,0 +1,159 @@
+# 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.
+# where to put generated libraries
+set(LIBRARY_OUTPUT_PATH "${BUILD_DIR}/src/vec")
+# where to put generated binaries
+set(EXECUTABLE_OUTPUT_PATH "${BUILD_DIR}/src/vec")
+
+set(VEC_FILES
+  aggregate_functions/aggregate_function_avg.cpp
+  aggregate_functions/aggregate_function_count.cpp
+  aggregate_functions/aggregate_function_distinct.cpp
+  aggregate_functions/aggregate_function_sum.cpp
+  aggregate_functions/aggregate_function_min_max.cpp
+  aggregate_functions/aggregate_function_null.cpp
+  aggregate_functions/aggregate_function_uniq.cpp
+  aggregate_functions/aggregate_function_hll_union_agg.cpp
+  aggregate_functions/aggregate_function_bitmap.cpp
+  aggregate_functions/aggregate_function_reader.cpp
+  aggregate_functions/aggregate_function_window.cpp
+  aggregate_functions/aggregate_function_stddev.cpp
+  aggregate_functions/aggregate_function_simple_factory.cpp
+  columns/collator.cpp
+  columns/column.cpp
+  columns/column_const.cpp
+  columns/column_decimal.cpp
+  columns/column_nullable.cpp
+  columns/column_string.cpp
+  columns/column_vector.cpp
+  columns/columns_common.cpp
+  common/demangle.cpp
+  common/exception.cpp
+  common/pod_array.cpp
+  common/string_utils/string_utils.cpp
+  core/block.cpp
+  core/block_info.cpp
+  core/column_with_type_and_name.cpp
+  core/field.cpp
+  core/field.cpp
+  core/sort_block.cpp
+  core/materialize_block.cpp
+  data_types/data_type.cpp
+  data_types/data_type_bitmap.cpp
+  data_types/data_type_nothing.cpp
+  data_types/data_type_nothing.cpp
+  data_types/data_type_nullable.cpp
+  data_types/data_type_nullable.cpp
+  data_types/data_type_number_base.cpp
+  data_types/data_type_string.cpp
+  data_types/data_type_decimal.cpp
+  data_types/get_least_supertype.cpp
+  data_types/nested_utils.cpp
+  data_types/data_type_date.cpp
+  data_types/data_type_date_time.cpp
+  exec/vaggregation_node.cpp
+  exec/ves_http_scan_node.cpp
+  exec/ves_http_scanner.cpp
+  exec/volap_scan_node.cpp
+  exec/vsort_node.cpp
+  exec/vsort_exec_exprs.cpp
+  exec/volap_scanner.cpp
+  exec/vexchange_node.cpp
+  exec/vset_operation_node.cpp
+  exec/vunion_node.cpp
+  exec/vintersect_node.cpp
+  exec/vexcept_node.cpp
+  exec/vselect_node.cpp
+  exec/vblocking_join_node.cpp
+  exec/vcross_join_node.cpp
+  exec/vodbc_scan_node.cpp
+  exec/vmysql_scan_node.cpp
+  exec/vschema_scan_node.cpp
+  exec/vempty_set_node.cpp
+  exec/vanalytic_eval_node.cpp
+  exec/vassert_num_rows_node.cpp
+  exec/vrepeat_node.cpp
+  exec/join/vhash_join_node.cpp
+  exprs/vectorized_agg_fn.cpp
+  exprs/vectorized_fn_call.cpp
+  exprs/vexpr.cpp
+  exprs/vexpr_context.cpp
+  exprs/vliteral.cpp
+  exprs/vin_predicate.cpp
+  exprs/vslot_ref.cpp
+  exprs/vcast_expr.cpp
+  exprs/vcase_expr.cpp
+  exprs/vinfo_func.cpp
+  functions/math.cpp
+  functions/function_bitmap.cpp
+  functions/comparison.cpp
+  functions/comparison_less.cpp
+  functions/comparison_equals.cpp
+  functions/comparison_greater.cpp
+  functions/function.cpp
+  functions/function_helpers.cpp
+  functions/function_hash.cpp
+  functions/functions_logical.cpp
+  functions/function_case.cpp
+  functions/function_cast.cpp
+  functions/function_conv.cpp
+  functions/function_string.cpp
+  functions/function_timestamp.cpp
+  functions/function_utility.cpp
+  functions/comparison_equal_for_null.cpp
+  functions/function_json.cpp
+  functions/hll_cardinality.cpp
+  functions/hll_empty.cpp
+  functions/hll_hash.cpp
+  functions/plus.cpp
+  functions/modulo.cpp
+  functions/multiply.cpp
+  functions/minus.cpp
+  functions/int_div.cpp
+  functions/divide.cpp
+  functions/function_bit.cpp
+  functions/is_null.cpp
+  functions/is_not_null.cpp
+  functions/in.cpp
+  functions/like.cpp
+  functions/to_time_function.cpp
+  functions/time_of_function.cpp
+  functions/if.cpp
+  functions/function_ifnull.cpp
+  functions/nullif.cpp
+  functions/random.cpp
+  functions/function_coalesce.cpp
+  functions/function_date_or_datetime_computation.cpp
+  functions/function_date_or_datetime_to_string.cpp
+  functions/function_datetime_string_to_string.cpp
+  functions/function_grouping.cpp
+  olap/vgeneric_iterators.cpp
+  olap/vcollect_iterator.cpp
+  olap/block_reader.cpp
+  sink/mysql_result_writer.cpp
+  sink/result_sink.cpp
+  sink/vdata_stream_sender.cpp
+  sink/vtabet_sink.cpp
+  runtime/vdatetime_value.cpp
+  runtime/vdata_stream_recvr.cpp
+  runtime/vdata_stream_mgr.cpp
+  runtime/vpartition_info.cpp
+  runtime/vsorted_run_merger.cpp)
+
+add_library(Vec STATIC
+    ${VEC_FILES}
+)
diff --git a/be/src/vec/aggregate_functions/aggregate_function.h b/be/src/vec/aggregate_functions/aggregate_function.h
new file mode 100644
index 0000000..4c2ef36
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function.h
@@ -0,0 +1,242 @@
+// 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/AggregateFunctions/IAggregateFunction.h
+// and modified by Doris
+
+#pragma once
+
+#include <cstddef>
+#include <istream>
+#include <memory>
+#include <ostream>
+#include <type_traits>
+#include <vector>
+
+#include "vec/common/exception.h"
+#include "vec/core/block.h"
+#include "vec/core/column_numbers.h"
+#include "vec/core/field.h"
+#include "vec/core/types.h"
+
+namespace doris::vectorized {
+
+class Arena;
+class IColumn;
+class IDataType;
+
+using DataTypePtr = std::shared_ptr<const IDataType>;
+using DataTypes = std::vector<DataTypePtr>;
+
+using AggregateDataPtr = char*;
+using ConstAggregateDataPtr = const char*;
+
+/** Aggregate functions interface.
+  * Instances of classes with this interface do not contain the data itself for aggregation,
+  *  but contain only metadata (description) of the aggregate function,
+  *  as well as methods for creating, deleting and working with data.
+  * The data resulting from the aggregation (intermediate computing states) is stored in other objects
+  *  (which can be created in some memory pool),
+  *  and IAggregateFunction is the external interface for manipulating them.
+  */
+class IAggregateFunction {
+public:
+    IAggregateFunction(const DataTypes& argument_types_, const Array& parameters_)
+            : argument_types(argument_types_), parameters(parameters_) {}
+
+    /// Get main function name.
+    virtual String get_name() const = 0;
+
+    /// Get the result type.
+    virtual DataTypePtr get_return_type() const = 0;
+
+    virtual ~IAggregateFunction() {}
+
+    /** Create empty data for aggregation with `placement new` at the specified location.
+      * You will have to destroy them using the `destroy` method.
+      */
+    virtual void create(AggregateDataPtr __restrict place) const = 0;
+
+    /// Delete data for aggregation.
+    virtual void destroy(AggregateDataPtr __restrict place) const noexcept = 0;
+
+    /// Reset aggregation state
+    virtual void reset(AggregateDataPtr place) const = 0;
+
+    /// It is not necessary to delete data.
+    virtual bool has_trivial_destructor() const = 0;
+
+    /// Get `sizeof` of structure with data.
+    virtual size_t size_of_data() const = 0;
+
+    /// How the data structure should be aligned. NOTE: Currently not used (structures with aggregation state are put without alignment).
+    virtual size_t align_of_data() const = 0;
+
+    /** Adds a value into aggregation data on which place points to.
+     *  columns points to columns containing arguments of aggregation function.
+     *  row_num is number of row which should be added.
+     *  Additional parameter arena should be used instead of standard memory allocator if the addition requires memory allocation.
+     */
+    virtual void add(AggregateDataPtr __restrict place, const IColumn** columns, size_t row_num,
+                     Arena* arena) const = 0;
+
+    /// Merges state (on which place points to) with other state of current aggregation function.
+    virtual void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena* arena) const = 0;
+
+    /// Serializes state (to transmit it over the network, for example).
+    virtual void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const = 0;
+
+    /// Deserializes state. This function is called only for empty (just created) states.
+    virtual void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, Arena* arena) const = 0;
+
+    /// Returns true if a function requires Arena to handle own states (see add(), merge(), deserialize()).
+    virtual bool allocates_memory_in_arena() const { return false; }
+
+    /// Inserts results into a column.
+    virtual void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const = 0;
+
+    /** Returns true for aggregate functions of type -State.
+      * They are executed as other aggregate functions, but not finalized (return an aggregation state that can be combined with another).
+      */
+    virtual bool is_state() const { return false; }
+
+    /// if return false, during insert_result_into function, you colud get nullable result column, 
+    /// so could insert to null value by yourself, rather than by AggregateFunctionNullBase;
+    /// because you maybe be calculate a invalid value, but want to use null replace it;
+    virtual bool insert_to_null_default() const { return true; }
+
+    /** The inner loop that uses the function pointer is better than using the virtual function.
+      * The reason is that in the case of virtual functions GCC 5.1.2 generates code,
+      *  which, at each iteration of the loop, reloads the function address (the offset value in the virtual function table) from memory to the register.
+      * This gives a performance drop on simple queries around 12%.
+      * After the appearance of better compilers, the code can be removed.
+      */
+    using AddFunc = void (*)(const IAggregateFunction*, AggregateDataPtr, const IColumn**, size_t,
+                             Arena*);
+    virtual AddFunc get_address_of_add_function() const = 0;
+
+    /** Contains a loop with calls to "add" function. You can collect arguments into array "places"
+      *  and do a single call to "add_batch" for devirtualization and inlining.
+      */
+    virtual void add_batch(size_t batch_size, AggregateDataPtr* places, size_t place_offset,
+                           const IColumn** columns, Arena* arena) const = 0;
+
+    /** The same for single place.
+      */
+    virtual void add_batch_single_place(size_t batch_size, AggregateDataPtr place,
+                                        const IColumn** columns, Arena* arena) const = 0;
+
+    // only used at agg reader
+    virtual void add_batch_range(size_t batch_begin, size_t batch_end, AggregateDataPtr place,
+                                 const IColumn** columns, Arena* arena, bool has_null = false) = 0;
+
+    // only used at window function
+    virtual void add_range_single_place(int64_t partition_start, int64_t partition_end,
+                                        int64_t frame_start, int64_t frame_end,
+                                        AggregateDataPtr place, const IColumn** columns,
+                                        Arena* arena) const = 0;
+
+    /** This is used for runtime code generation to determine, which header files to include in generated source.
+      * Always implement it as
+      * const char * get_header_file_path() const override { return __FILE__; }
+      */
+    virtual const char* get_header_file_path() const = 0;
+
+    const DataTypes& get_argument_types() const { return argument_types; }
+    const Array& get_parameters() const { return parameters; }
+
+protected:
+    DataTypes argument_types;
+    Array parameters;
+};
+
+/// Implement method to obtain an address of 'add' function.
+template <typename Derived>
+class IAggregateFunctionHelper : public IAggregateFunction {
+private:
+    static void add_free(const IAggregateFunction* that, AggregateDataPtr place,
+                         const IColumn** columns, size_t row_num, Arena* arena) {
+        static_cast<const Derived&>(*that).add(place, columns, row_num, arena);
+    }
+
+public:
+    IAggregateFunctionHelper(const DataTypes& argument_types_, const Array& parameters_)
+            : IAggregateFunction(argument_types_, parameters_) {}
+
+    AddFunc get_address_of_add_function() const override { return &add_free; }
+
+    void add_batch(size_t batch_size, AggregateDataPtr* places, size_t place_offset,
+                   const IColumn** columns, Arena* arena) const override {
+        for (size_t i = 0; i < batch_size; ++i)
+            static_cast<const Derived*>(this)->add(places[i] + place_offset, columns, i, arena);
+    }
+
+    void add_batch_single_place(size_t batch_size, AggregateDataPtr place, const IColumn** columns,
+                                Arena* arena) const override {
+        for (size_t i = 0; i < batch_size; ++i)
+            static_cast<const Derived*>(this)->add(place, columns, i, arena);
+    }
+    //now this is use for sum/count/avg/min/max win function, other win function should override this function in class
+    void add_range_single_place(int64_t partition_start, int64_t partition_end, int64_t frame_start,
+                                int64_t frame_end, AggregateDataPtr place, const IColumn** columns,
+                                Arena* arena) const override {
+        frame_start = std::max<int64_t>(frame_start, partition_start);
+        frame_end = std::min<int64_t>(frame_end, partition_end);
+        for (int64_t i = frame_start; i < frame_end; ++i) {
+            static_cast<const Derived*>(this)->add(place, columns, i, arena);
+        }
+    }
+
+    void add_batch_range(size_t batch_begin, size_t batch_end, AggregateDataPtr place,
+                         const IColumn** columns, Arena* arena, bool has_null) override {
+        for (size_t i = batch_begin; i <= batch_end; ++i)
+            static_cast<const Derived*>(this)->add(place, columns, i, arena);
+    }
+};
+
+/// Implements several methods for manipulation with data. T - type of structure with data for aggregation.
+template <typename T, typename Derived>
+class IAggregateFunctionDataHelper : public IAggregateFunctionHelper<Derived> {
+protected:
+    using Data = T;
+
+    static Data& data(AggregateDataPtr __restrict place) { return *reinterpret_cast<Data*>(place); }
+    static const Data& data(ConstAggregateDataPtr __restrict place) {
+        return *reinterpret_cast<const Data*>(place);
+    }
+
+public:
+    IAggregateFunctionDataHelper(const DataTypes& argument_types_, const Array& parameters_)
+            : IAggregateFunctionHelper<Derived>(argument_types_, parameters_) {}
+
+    void create(AggregateDataPtr __restrict place) const override { new (place) Data; }
+
+    void destroy(AggregateDataPtr __restrict place) const noexcept override { data(place).~Data(); }
+
+    bool has_trivial_destructor() const override { return std::is_trivially_destructible_v<Data>; }
+
+    size_t size_of_data() const override { return sizeof(Data); }
+
+    /// NOTE: Currently not used (structures with aggregation state are put without alignment).
+    size_t align_of_data() const override { return alignof(Data); }
+
+    void reset(AggregateDataPtr place) const override {}
+};
+
+using AggregateFunctionPtr = std::shared_ptr<IAggregateFunction>;
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_avg.cpp b/be/src/vec/aggregate_functions/aggregate_function_avg.cpp
new file mode 100644
index 0000000..bb7605b
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_avg.cpp
@@ -0,0 +1,68 @@
+// 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/AggregateFunctions/AggregateFunctionAvg.cpp
+// and modified by Doris
+
+#include "vec/aggregate_functions/aggregate_function_avg.h"
+
+#include "common/logging.h"
+#include "vec/aggregate_functions/aggregate_function_simple_factory.h"
+#include "vec/aggregate_functions/factory_helpers.h"
+#include "vec/aggregate_functions/helpers.h"
+
+namespace doris::vectorized {
+
+namespace {
+
+template <typename T>
+struct Avg {
+    using FieldType = std::conditional_t<IsDecimalNumber<T>, Decimal128, NearestFieldType<T>>;
+    using Function = AggregateFunctionAvg<T, AggregateFunctionAvgData<FieldType>>;
+};
+
+template <typename T>
+using AggregateFuncAvg = typename Avg<T>::Function;
+
+AggregateFunctionPtr create_aggregate_function_avg(const std::string& name,
+                                                   const DataTypes& argument_types,
+                                                   const Array& parameters,
+                                                   const bool result_is_nullable) {
+    assert_no_parameters(name, parameters);
+    assert_unary(name, argument_types);
+
+    AggregateFunctionPtr res;
+    DataTypePtr data_type = argument_types[0];
+    if (is_decimal(data_type))
+        res.reset(
+                create_with_decimal_type<AggregateFuncAvg>(*data_type, *data_type, argument_types));
+    else
+        res.reset(create_with_numeric_type<AggregateFuncAvg>(*data_type, argument_types));
+
+    if (!res) {
+        LOG(WARNING) << fmt::format("Illegal type {} of argument for aggregate function {}",
+                                    argument_types[0]->get_name(), name);
+    }
+    return res;
+}
+
+} // namespace
+
+void register_aggregate_function_avg(AggregateFunctionSimpleFactory& factory) {
+    factory.register_function("avg", create_aggregate_function_avg);
+}
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_avg.h b/be/src/vec/aggregate_functions/aggregate_function_avg.h
new file mode 100644
index 0000000..18584ee
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_avg.h
@@ -0,0 +1,128 @@
+// 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/AggregateFunctions/AggregateFunctionAvg.h
+// and modified by Doris
+
+#pragma once
+
+#include "common/status.h"
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/columns/columns_number.h"
+#include "vec/data_types/data_type_decimal.h"
+#include "vec/data_types/data_type_number.h"
+#include "vec/io/io_helper.h"
+
+namespace doris::vectorized {
+
+template <typename T>
+struct AggregateFunctionAvgData {
+    T sum = 0;
+    UInt64 count = 0;
+
+    template <typename ResultT>
+    ResultT result() const {
+        if constexpr (std::is_floating_point_v<ResultT>)
+            if constexpr (std::numeric_limits<ResultT>::is_iec559)
+                return static_cast<ResultT>(sum) / count; /// allow division by zero
+
+        if (!count)
+            throw Exception("AggregateFunctionAvg with zero values", TStatusCode::VEC_LOGIC_ERROR);
+        return static_cast<ResultT>(sum) / count;
+    }
+
+    void write(BufferWritable& buf) const {
+        write_binary(sum, buf);
+        write_binary(count, buf);
+    }
+
+    void read(BufferReadable& buf) {
+        read_binary(sum, buf);
+        read_binary(count, buf);
+    }
+};
+
+/// Calculates arithmetic mean of numbers.
+template <typename T, typename Data>
+class AggregateFunctionAvg final
+        : public IAggregateFunctionDataHelper<Data, AggregateFunctionAvg<T, Data>> {
+public:
+    using ResultType = std::conditional_t<IsDecimalNumber<T>, Decimal128, Float64>;
+    using ResultDataType = std::conditional_t<IsDecimalNumber<T>, DataTypeDecimal<Decimal128>,
+                                              DataTypeNumber<Float64>>;
+    using ColVecType = std::conditional_t<IsDecimalNumber<T>, ColumnDecimal<T>, ColumnVector<T>>;
+    using ColVecResult = std::conditional_t<IsDecimalNumber<T>, ColumnDecimal<Decimal128>,
+                                            ColumnVector<Float64>>;
+
+    /// ctor for native types
+    AggregateFunctionAvg(const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper<Data, AggregateFunctionAvg<T, Data>>(argument_types_,
+                                                                                {}),
+              scale(0) {}
+
+    /// ctor for Decimals
+    AggregateFunctionAvg(const IDataType& data_type, const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper<Data, AggregateFunctionAvg<T, Data>>(argument_types_,
+                                                                                {}),
+              scale(get_decimal_scale(data_type)) {}
+
+    String get_name() const override { return "avg"; }
+
+    DataTypePtr get_return_type() const override {
+        if constexpr (IsDecimalNumber<T>)
+            return std::make_shared<ResultDataType>(ResultDataType::max_precision(), scale);
+        else
+            return std::make_shared<ResultDataType>();
+    }
+
+    void add(AggregateDataPtr __restrict place, const IColumn** columns, size_t row_num,
+             Arena*) const override {
+        const auto& column = static_cast<const ColVecType&>(*columns[0]);
+        this->data(place).sum += column.get_data()[row_num];
+        ++this->data(place).count;
+    }
+
+    void reset(AggregateDataPtr place) const override {
+        this->data(place).sum = 0;
+        this->data(place).count = 0;
+    }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena*) const override {
+        this->data(place).sum += this->data(rhs).sum;
+        this->data(place).count += this->data(rhs).count;
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        this->data(place).write(buf);
+    }
+
+    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, Arena*) const override {
+        this->data(place).read(buf);
+    }
+
+    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
+        auto& column = static_cast<ColVecResult&>(to);
+        column.get_data().push_back(this->data(place).template result<ResultType>());
+    }
+
+    const char* get_header_file_path() const override { return __FILE__; }
+
+private:
+    UInt32 scale;
+};
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_bitmap.cpp b/be/src/vec/aggregate_functions/aggregate_function_bitmap.cpp
new file mode 100644
index 0000000..d110b09
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_bitmap.cpp
@@ -0,0 +1,87 @@
+// 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.
+
+#include "vec/aggregate_functions/aggregate_function_bitmap.h"
+
+#include "vec/aggregate_functions/aggregate_function_simple_factory.h"
+
+namespace doris::vectorized {
+
+template <bool nullable, template <bool, typename> class AggregateFunctionTemplate>
+static IAggregateFunction* createWithIntDataType(const DataTypes& argument_type) {
+    auto type = argument_type[0].get();
+    if (type->is_nullable()) {
+        type = assert_cast<const DataTypeNullable*>(type)->get_nested_type().get();
+    }
+    WhichDataType which(type);
+    if (which.idx == TypeIndex::Int8)
+        return new AggregateFunctionTemplate<nullable, ColumnVector<Int8>>(argument_type);
+    if (which.idx == TypeIndex::Int16)
+        return new AggregateFunctionTemplate<nullable, ColumnVector<Int16>>(argument_type);
+    if (which.idx == TypeIndex::Int32)
+        return new AggregateFunctionTemplate<nullable, ColumnVector<Int32>>(argument_type);
+    if (which.idx == TypeIndex::Int64)
+        return new AggregateFunctionTemplate<nullable, ColumnVector<Int64>>(argument_type);
+    return nullptr;
+}
+
+AggregateFunctionPtr create_aggregate_function_bitmap_union(const std::string& name,
+                                                            const DataTypes& argument_types,
+                                                            const Array& parameters,
+                                                            const bool result_is_nullable) {
+    return std::make_shared<AggregateFunctionBitmapOp<AggregateFunctionBitmapUnionOp>>(
+            argument_types);
+}
+
+AggregateFunctionPtr create_aggregate_function_bitmap_intersect(const std::string& name,
+                                                                const DataTypes& argument_types,
+                                                                const Array& parameters,
+                                                                const bool result_is_nullable) {
+    return std::make_shared<AggregateFunctionBitmapOp<AggregateFunctionBitmapIntersectOp>>(
+            argument_types);
+}
+template <bool nullable>
+AggregateFunctionPtr create_aggregate_function_bitmap_union_count(const std::string& name,
+                                                                  const DataTypes& argument_types,
+                                                                  const Array& parameters,
+                                                                  const bool result_is_nullable) {
+    return std::make_shared<AggregateFunctionBitmapCount<nullable, ColumnBitmap>>(argument_types);
+}
+
+template <bool nullable>
+AggregateFunctionPtr create_aggregate_function_bitmap_union_int(const std::string& name,
+                                                                const DataTypes& argument_types,
+                                                                const Array& parameters,
+                                                                const bool result_is_nullable) {
+    return std::shared_ptr<IAggregateFunction>(
+            createWithIntDataType<nullable, AggregateFunctionBitmapCount>(argument_types));
+}
+
+void register_aggregate_function_bitmap(AggregateFunctionSimpleFactory& factory) {
+    factory.register_function("bitmap_union", create_aggregate_function_bitmap_union);
+    factory.register_function("bitmap_intersect", create_aggregate_function_bitmap_intersect);
+    factory.register_function("bitmap_union_count",
+                              create_aggregate_function_bitmap_union_count<false>);
+    factory.register_function("bitmap_union_count",
+                              create_aggregate_function_bitmap_union_count<true>, true);
+
+    factory.register_function("bitmap_union_int",
+                              create_aggregate_function_bitmap_union_int<false>);
+    factory.register_function("bitmap_union_int", create_aggregate_function_bitmap_union_int<true>,
+                              true);
+}
+} // namespace doris::vectorized
\ No newline at end of file
diff --git a/be/src/vec/aggregate_functions/aggregate_function_bitmap.h b/be/src/vec/aggregate_functions/aggregate_function_bitmap.h
new file mode 100644
index 0000000..a2e43e5
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_bitmap.h
@@ -0,0 +1,175 @@
+// 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 <istream>
+#include <ostream>
+
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/columns/column_complex.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/common/assert_cast.h"
+#include "vec/data_types/data_type_bitmap.h"
+#include "vec/data_types/data_type_nullable.h"
+#include "vec/data_types/data_type_number.h"
+#include "vec/io/io_helper.h"
+
+namespace doris::vectorized {
+
+struct AggregateFunctionBitmapUnionOp {
+    static constexpr auto name = "bitmap_union";
+
+    template <typename T>
+    static void add(BitmapValue& res, const T& data) {
+        res.add(data);
+    }
+
+    static void add(BitmapValue& res, const BitmapValue& data) { res |= data; }
+
+    static void merge(BitmapValue& res, const BitmapValue& data) { res |= data; }
+};
+
+struct AggregateFunctionBitmapIntersectOp {
+    static constexpr auto name = "bitmap_intersect";
+    static void add(BitmapValue& res, const BitmapValue& data) { res &= data; }
+
+    static void merge(BitmapValue& res, const BitmapValue& data) { res &= data; }
+};
+
+template <typename Op>
+struct AggregateFunctionBitmapData {
+    BitmapValue value;
+
+    template <typename T>
+    void add(const T& data) {
+        Op::add(value, data);
+    }
+
+    void merge(const BitmapValue& data) { Op::merge(value, data); }
+
+    void write(BufferWritable& buf) const { DataTypeBitMap::serialize_as_stream(value, buf); }
+
+    void read(BufferReadable& buf) { DataTypeBitMap::deserialize_as_stream(value, buf); }
+
+    BitmapValue& get() { return value; }
+};
+
+template <typename Op>
+class AggregateFunctionBitmapOp final
+        : public IAggregateFunctionDataHelper<AggregateFunctionBitmapData<Op>,
+                                              AggregateFunctionBitmapOp<Op>> {
+public:
+    using ResultDataType = BitmapValue;
+    using ColVecType = ColumnBitmap;
+    using ColVecResult = ColumnBitmap;
+
+    String get_name() const override { return Op::name; }
+
+    AggregateFunctionBitmapOp(const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper<AggregateFunctionBitmapData<Op>,
+                                           AggregateFunctionBitmapOp<Op>>(argument_types_, {}) {}
+
+    DataTypePtr get_return_type() const override { return std::make_shared<DataTypeBitMap>(); }
+
+    void add(AggregateDataPtr __restrict place, const IColumn** columns, size_t row_num,
+             Arena*) const override {
+        const auto& column = static_cast<const ColVecType&>(*columns[0]);
+        this->data(place).add(column.get_data()[row_num]);
+    }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena*) const override {
+        this->data(place).merge(
+                const_cast<AggregateFunctionBitmapData<Op>&>(this->data(rhs)).get());
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        this->data(place).write(buf);
+    }
+
+    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, Arena*) const override {
+        this->data(place).read(buf);
+    }
+
+    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
+        auto& column = static_cast<ColVecResult&>(to);
+        column.get_data().push_back(
+                const_cast<AggregateFunctionBitmapData<Op>&>(this->data(place)).get());
+    }
+
+    const char* get_header_file_path() const override { return __FILE__; }
+};
+
+template <bool nullable, typename ColVecType>
+class AggregateFunctionBitmapCount final
+        : public IAggregateFunctionDataHelper<
+                  AggregateFunctionBitmapData<AggregateFunctionBitmapUnionOp>,
+                  AggregateFunctionBitmapCount<nullable, ColVecType>> {
+public:
+    // using ColVecType = ColumnBitmap;
+    using ColVecResult = ColumnVector<Int64>;
+    using AggFunctionData = AggregateFunctionBitmapData<AggregateFunctionBitmapUnionOp>;
+
+    AggregateFunctionBitmapCount(const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper<
+                      AggregateFunctionBitmapData<AggregateFunctionBitmapUnionOp>,
+                      AggregateFunctionBitmapCount<nullable, ColVecType>>(argument_types_, {}) {}
+
+    String get_name() const override { return "count"; }
+    DataTypePtr get_return_type() const override { return std::make_shared<DataTypeInt64>(); }
+
+    void add(AggregateDataPtr __restrict place, const IColumn** columns, size_t row_num,
+             Arena*) const override {
+        if constexpr (nullable) {
+            auto& nullable_column = assert_cast<const ColumnNullable&>(*columns[0]);
+            if (!nullable_column.is_null_at(row_num)) {
+                const auto& column =
+                        static_cast<const ColVecType&>(nullable_column.get_nested_column());
+                this->data(place).add(column.get_data()[row_num]);
+            }
+        } else {
+            const auto& column = static_cast<const ColVecType&>(*columns[0]);
+            this->data(place).add(column.get_data()[row_num]);
+        }
+    }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena*) const override {
+        this->data(place).merge(const_cast<AggFunctionData&>(this->data(rhs)).get());
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        this->data(place).write(buf);
+    }
+
+    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, Arena*) const override {
+        this->data(place).read(buf);
+    }
+
+    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
+        auto& value_data = const_cast<AggFunctionData&>(this->data(place)).get();
+        auto& column = static_cast<ColVecResult&>(to);
+        column.get_data().push_back(value_data.cardinality());
+    }
+
+    const char* get_header_file_path() const override { return __FILE__; }
+};
+
+AggregateFunctionPtr create_aggregate_function_bitmap_union(const std::string& name,
+                                                            const DataTypes& argument_types,
+                                                            const Array& parameters,
+                                                            const bool result_is_nullable);
+
+} // namespace doris::vectorized
\ No newline at end of file
diff --git a/be/src/vec/aggregate_functions/aggregate_function_combinator.h b/be/src/vec/aggregate_functions/aggregate_function_combinator.h
new file mode 100644
index 0000000..77d465b
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_combinator.h
@@ -0,0 +1,81 @@
+// 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/AggregateFunctions/IAggregateFunctionCombinator.h
+// and modified by Doris
+
+#pragma once
+
+#include <vec/aggregate_functions/aggregate_function.h>
+#include <vec/data_types/data_type.h>
+
+#include <memory>
+
+namespace doris::vectorized {
+
+/** Aggregate function combinator allows to take one aggregate function
+  *  and transform it to another aggregate function.
+  *
+  * In SQL language they are used as suffixes for existing aggregate functions.
+  *
+  * Example: -If combinator takes an aggregate function and transforms it
+  *  to aggregate function with additional argument at end (condition),
+  *  that will pass values to original aggregate function when the condition is true.
+  *
+  * More examples:
+  *
+  * sum(x) - calculate sum of x
+  * sumIf(x, cond) - calculate sum of x for rows where condition is true.
+  * sumArray(arr) - calculate sum of all elements of arrays.
+  *
+  * PS. Please don't mess it with so called "combiner" - totally unrelated notion from Hadoop world.
+  * "combining" - merging the states of aggregate functions - is supported naturally in ClickHouse.
+  */
+
+class IAggregateFunctionCombinator {
+public:
+    virtual String get_name() const = 0;
+
+    virtual bool is_for_internal_usage_only() const { return false; }
+
+    /** From the arguments for combined function (ex: UInt64, UInt8 for sumIf),
+      *  get the arguments for nested function (ex: UInt64 for sum).
+      * If arguments are not suitable for combined function, throw an exception.
+      */
+    virtual DataTypes transform_arguments(const DataTypes& arguments) const { return arguments; }
+
+    /** From the parameters for combined function,
+      *  get the parameters for nested function.
+      * If arguments are not suitable for combined function, throw an exception.
+      */
+    virtual Array transform_parameters(const Array& parameters) const { return parameters; }
+
+    /** Create combined aggregate function (ex: sumIf)
+      *  from nested function (ex: sum)
+      *  and arguments for combined agggregate function (ex: UInt64, UInt8 for sumIf).
+      * It's assumed that function transform_arguments was called before this function and 'arguments' are validated.
+      */
+    virtual AggregateFunctionPtr transform_aggregate_function(
+            const AggregateFunctionPtr& nested_function, const DataTypes& arguments,
+            const Array& params, const bool result_is_nullable) const = 0;
+
+    virtual ~IAggregateFunctionCombinator() {}
+};
+
+using AggregateFunctionCombinatorPtr = std::shared_ptr<const IAggregateFunctionCombinator>;
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_count.cpp b/be/src/vec/aggregate_functions/aggregate_function_count.cpp
new file mode 100644
index 0000000..aa5d006
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_count.cpp
@@ -0,0 +1,52 @@
+// 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/AggregateFunctions/AggregateFunctionCount.cpp
+// and modified by Doris
+
+#include "vec/aggregate_functions/aggregate_function_count.h"
+
+#include "vec/aggregate_functions/aggregate_function_simple_factory.h"
+#include "vec/aggregate_functions/factory_helpers.h"
+
+namespace doris::vectorized {
+
+AggregateFunctionPtr create_aggregate_function_count(const std::string& name,
+                                                     const DataTypes& argument_types,
+                                                     const Array& parameters,
+                                                     const bool result_is_nullable) {
+    assert_no_parameters(name, parameters);
+    assert_arity_at_most<1>(name, argument_types);
+
+    return std::make_shared<AggregateFunctionCount>(argument_types);
+}
+
+AggregateFunctionPtr create_aggregate_function_count_not_null_unary(const std::string& name,
+                                                                    const DataTypes& argument_types,
+                                                                    const Array& parameters,
+                                                                    const bool result_is_nullable) {
+    assert_arity_at_most<1>(name, argument_types);
+
+    return std::make_shared<AggregateFunctionCountNotNullUnary>(argument_types);
+}
+
+void register_aggregate_function_count(AggregateFunctionSimpleFactory& factory) {
+    factory.register_function("count", create_aggregate_function_count);
+    factory.register_function("count", create_aggregate_function_count_not_null_unary, true);
+}
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_count.h b/be/src/vec/aggregate_functions/aggregate_function_count.h
new file mode 100644
index 0000000..fd096dc
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_count.h
@@ -0,0 +1,122 @@
+// 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/AggregateFunctions/AggregateFunctionCount.h
+// and modified by Doris
+
+#pragma once
+
+#include <array>
+
+#include "common/logging.h"
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/common/assert_cast.h"
+#include "vec/data_types/data_type_number.h"
+#include "vec/io/io_helper.h"
+
+namespace doris::vectorized {
+
+struct AggregateFunctionCountData {
+    UInt64 count = 0;
+};
+
+/// Simply count number of calls.
+class AggregateFunctionCount final
+        : public IAggregateFunctionDataHelper<AggregateFunctionCountData, AggregateFunctionCount> {
+public:
+    AggregateFunctionCount(const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper(argument_types_, {}) {}
+
+    String get_name() const override { return "count"; }
+
+    DataTypePtr get_return_type() const override { return std::make_shared<DataTypeInt64>(); }
+
+    void add(AggregateDataPtr __restrict place, const IColumn**, size_t, Arena*) const override {
+        ++data(place).count;
+    }
+
+    void reset(AggregateDataPtr place) const override {
+        this->data(place).count = 0;
+    }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena*) const override {
+        data(place).count += data(rhs).count;
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        write_var_uint(data(place).count, buf);
+    }
+
+    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, Arena*) const override {
+        read_var_uint(data(place).count, buf);
+    }
+
+    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
+        assert_cast<ColumnInt64&>(to).get_data().push_back(data(place).count);
+    }
+
+    const char* get_header_file_path() const override { return __FILE__; }
+};
+
+/// Simply count number of not-NULL values.
+class AggregateFunctionCountNotNullUnary final
+        : public IAggregateFunctionDataHelper<AggregateFunctionCountData,
+                                              AggregateFunctionCountNotNullUnary> {
+public:
+    AggregateFunctionCountNotNullUnary(const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper(argument_types_, {}) {}
+
+    String get_name() const override { return "count"; }
+
+    DataTypePtr get_return_type() const override { return std::make_shared<DataTypeInt64>(); }
+
+    void add(AggregateDataPtr __restrict place, const IColumn** columns, size_t row_num,
+             Arena*) const override {
+        data(place).count += !assert_cast<const ColumnNullable&>(*columns[0]).is_null_at(row_num);
+    }
+
+    void reset(AggregateDataPtr place) const override {
+        data(place).count = 0;
+    }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena*) const override {
+        data(place).count += data(rhs).count;
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        write_var_uint(data(place).count, buf);
+    }
+
+    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, Arena*) const override {
+        read_var_uint(data(place).count, buf);
+    }
+
+    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
+        if (to.is_nullable()) {
+            auto& null_column = assert_cast<ColumnNullable &>(to);
+            null_column.get_null_map_data().push_back(0);
+            assert_cast<ColumnInt64 &>(null_column.get_nested_column()).get_data().push_back(data(place).count);
+        } else {
+            assert_cast<ColumnInt64 &>(to).get_data().push_back(data(place).count);
+        }
+    }
+
+    const char* get_header_file_path() const override { return __FILE__; }
+};
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_distinct.cpp b/be/src/vec/aggregate_functions/aggregate_function_distinct.cpp
new file mode 100644
index 0000000..af64a3a
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_distinct.cpp
@@ -0,0 +1,96 @@
+// 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/AggregateFunctions/AggregateFunctionDistinct.cpp
+// and modified by Doris
+
+#include <algorithm>
+#include <boost/algorithm/string.hpp>
+
+#include "vec/aggregate_functions/aggregate_function_combinator.h"
+#include "vec/aggregate_functions/aggregate_function_distinct.h"
+#include "vec/aggregate_functions/aggregate_function_simple_factory.h"
+#include "vec/aggregate_functions/helpers.h"
+#include "vec/common/typeid_cast.h"
+#include "vec/data_types/data_type_nullable.h"
+
+namespace doris::vectorized {
+
+class AggregateFunctionCombinatorDistinct final : public IAggregateFunctionCombinator {
+public:
+    String get_name() const override { return "Distinct"; }
+
+    DataTypes transform_arguments(const DataTypes& arguments) const override {
+        if (arguments.empty()) {
+            LOG(FATAL)
+                    << "Incorrect number of arguments for aggregate function with Distinct suffix";
+        }
+        return arguments;
+    }
+
+    AggregateFunctionPtr transform_aggregate_function(const AggregateFunctionPtr& nested_function,
+                                                      const DataTypes& arguments,
+                                                      const Array& params,
+                                                      const bool result_is_nullable) const override {
+        DCHECK(nested_function != nullptr);
+        if (nested_function == nullptr) return nullptr;
+        
+        AggregateFunctionPtr res;
+        if (arguments.size() == 1) {
+            res.reset(create_with_numeric_type<AggregateFunctionDistinct,
+                                               AggregateFunctionDistinctSingleNumericData>(
+                    *arguments[0], nested_function, arguments));
+
+            if (res) return res;
+
+            if (arguments[0]->is_value_unambiguously_represented_in_contiguous_memory_region())
+                return std::make_shared<AggregateFunctionDistinct<
+                        AggregateFunctionDistinctSingleGenericData<true>>>(nested_function,
+                                                                           arguments);
+            else
+                return std::make_shared<AggregateFunctionDistinct<
+                        AggregateFunctionDistinctSingleGenericData<false>>>(nested_function,
+                                                                            arguments);
+        }
+
+        return std::make_shared<
+                AggregateFunctionDistinct<AggregateFunctionDistinctMultipleGenericData>>(
+                nested_function, arguments);
+    }
+};
+
+const std::string DISTINCT_FUNCTION_PREFIX = "multi_distinct_";
+
+void register_aggregate_function_combinator_distinct(AggregateFunctionSimpleFactory& factory) {
+    AggregateFunctionCreator creator = [&](const std::string& name, const DataTypes& types,
+                                           const Array& params, const bool result_is_nullable) {
+        // 1. we should get not nullable types;
+        DataTypes nested_types(types.size());
+        std::transform(types.begin(), types.end(), nested_types.begin(),
+                       [](const auto& e) { return remove_nullable(e); });
+        auto function_combinator = std::make_shared<AggregateFunctionCombinatorDistinct>();
+        auto transform_arguments = function_combinator->transform_arguments(nested_types);
+        if (!boost::algorithm::starts_with(name, DISTINCT_FUNCTION_PREFIX)) {
+            return AggregateFunctionPtr();
+        }
+        auto nested_function_name = name.substr(DISTINCT_FUNCTION_PREFIX.size());
+        auto nested_function = factory.get(nested_function_name, transform_arguments, params);
+        return function_combinator->transform_aggregate_function(nested_function, types, params, result_is_nullable);
+    };
+    factory.register_distinct_function_combinator(creator, DISTINCT_FUNCTION_PREFIX);
+}
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_distinct.h b/be/src/vec/aggregate_functions/aggregate_function_distinct.h
new file mode 100644
index 0000000..6502b48
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_distinct.h
@@ -0,0 +1,224 @@
+// 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/AggregateFunctions/AggregateFunctionDistinct.h
+// and modified by Doris
+
+#pragma once
+
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/aggregate_functions/key_holder_helpers.h"
+#include "vec/common/aggregation_common.h"
+#include "vec/common/assert_cast.h"
+#include "vec/common/field_visitors.h"
+#include "vec/common/hash_table/hash_set.h"
+#include "vec/common/hash_table/hash_table.h"
+#include "vec/common/sip_hash.h"
+#include "vec/io/io_helper.h"
+
+namespace doris::vectorized {
+
+template <typename T>
+struct AggregateFunctionDistinctSingleNumericData {
+    /// When creating, the hash table must be small.
+    using Set = HashSetWithStackMemory<T, DefaultHash<T>, 4>;
+    using Self = AggregateFunctionDistinctSingleNumericData<T>;
+    Set set;
+
+    void add(const IColumn** columns, size_t /* columns_num */, size_t row_num, Arena*) {
+        const auto& vec = assert_cast<const ColumnVector<T>&>(*columns[0]).get_data();
+        set.insert(vec[row_num]);
+    }
+
+    void merge(const Self& rhs, Arena*) { set.merge(rhs.set); }
+
+    void serialize(BufferWritable& buf) const { set.write(buf); }
+
+    void deserialize(BufferReadable& buf, Arena*) { set.read(buf); }
+
+    MutableColumns get_arguments(const DataTypes& argument_types) const {
+        MutableColumns argument_columns;
+        argument_columns.emplace_back(argument_types[0]->create_column());
+        for (const auto& elem : set) argument_columns[0]->insert(elem.get_value());
+
+        return argument_columns;
+    }
+};
+
+struct AggregateFunctionDistinctGenericData {
+    /// When creating, the hash table must be small.
+    using Set = HashSetWithSavedHashWithStackMemory<StringRef, StringRefHash, 4>;
+    using Self = AggregateFunctionDistinctGenericData;
+    Set set;
+
+    void merge(const Self& rhs, Arena* arena) {
+        Set::LookupResult it;
+        bool inserted;
+        for (const auto& elem : rhs.set)
+            set.emplace(ArenaKeyHolder{elem.get_value(), *arena}, it, inserted);
+    }
+
+    void serialize(BufferWritable& buf) const {
+        write_var_uint(set.size(), buf);
+        for (const auto& elem : set)
+            write_string_binary(elem.get_value(), buf);
+    }
+
+    void deserialize(BufferReadable& buf, Arena* arena) {
+        size_t size;
+        read_var_uint(size, buf);
+
+        StringRef ref;
+        for (size_t i = 0; i < size; ++i) {
+            read_string_binary(ref, buf);
+            set.insert(ref);
+        }
+    }
+};
+
+template <bool is_plain_column>
+struct AggregateFunctionDistinctSingleGenericData : public AggregateFunctionDistinctGenericData {
+    void add(const IColumn** columns, size_t /* columns_num */, size_t row_num, Arena* arena) {
+        Set::LookupResult it;
+        bool inserted;
+        auto key_holder = get_key_holder<is_plain_column>(*columns[0], row_num, *arena);
+        set.emplace(key_holder, it, inserted);
+    }
+
+    MutableColumns get_arguments(const DataTypes& argument_types) const {
+        MutableColumns argument_columns;
+        argument_columns.emplace_back(argument_types[0]->create_column());
+        for (const auto& elem : set)
+            deserialize_and_insert<is_plain_column>(elem.get_value(), *argument_columns[0]);
+
+        return argument_columns;
+    }
+};
+
+struct AggregateFunctionDistinctMultipleGenericData : public AggregateFunctionDistinctGenericData {
+    void add(const IColumn** columns, size_t columns_num, size_t row_num, Arena* arena) {
+        const char* begin = nullptr;
+        StringRef value(begin, 0);
+        for (size_t i = 0; i < columns_num; ++i) {
+            auto cur_ref = columns[i]->serialize_value_into_arena(row_num, *arena, begin);
+            value.data = cur_ref.data - value.size;
+            value.size += cur_ref.size;
+        }
+
+        Set::LookupResult it;
+        bool inserted;
+        auto key_holder = SerializedKeyHolder{value, *arena};
+        set.emplace(key_holder, it, inserted);
+    }
+
+    MutableColumns get_arguments(const DataTypes& argument_types) const {
+        MutableColumns argument_columns(argument_types.size());
+        for (size_t i = 0; i < argument_types.size(); ++i)
+            argument_columns[i] = argument_types[i]->create_column();
+
+        for (const auto& elem : set) {
+            const char* begin = elem.get_value().data;
+            for (auto& column : argument_columns)
+                begin = column->deserialize_and_insert_from_arena(begin);
+        }
+
+        return argument_columns;
+    }
+};
+
+/** Adaptor for aggregate functions.
+  * Adding -Distinct suffix to aggregate function
+**/
+template <typename Data>
+class AggregateFunctionDistinct
+        : public IAggregateFunctionDataHelper<Data, AggregateFunctionDistinct<Data>> {
+private:
+    static constexpr auto prefix_size = sizeof(Data);
+    AggregateFunctionPtr nested_func;
+    size_t arguments_num;
+
+    AggregateDataPtr get_nested_place(AggregateDataPtr __restrict place) const noexcept {
+        return place + prefix_size;
+    }
+
+    ConstAggregateDataPtr get_nested_place(ConstAggregateDataPtr __restrict place) const noexcept {
+        return place + prefix_size;
+    }
+
+public:
+    AggregateFunctionDistinct(AggregateFunctionPtr nested_func_, const DataTypes& arguments)
+            : IAggregateFunctionDataHelper<Data, AggregateFunctionDistinct>(
+                      arguments, nested_func_->get_parameters()),
+              nested_func(nested_func_),
+              arguments_num(arguments.size()) {}
+
+    void add(AggregateDataPtr __restrict place, const IColumn** columns, size_t row_num,
+             Arena* arena) const override {
+        this->data(place).add(columns, arguments_num, row_num, arena);
+    }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs,
+               Arena* arena) const override {
+        this->data(place).merge(this->data(rhs), arena);
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        this->data(place).serialize(buf);
+    }
+
+    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, Arena* arena) const override {
+        this->data(place).deserialize(buf, arena);
+    }
+
+    // void insert_result_into(AggregateDataPtr place, IColumn & to, Arena * arena) const override
+    void insert_result_into(ConstAggregateDataPtr targetplace, IColumn& to) const override {
+        auto place = const_cast<AggregateDataPtr>(targetplace);
+        auto arguments = this->data(place).get_arguments(this->argument_types);
+        ColumnRawPtrs arguments_raw(arguments.size());
+        for (size_t i = 0; i < arguments.size(); ++i) arguments_raw[i] = arguments[i].get();
+
+        assert(!arguments.empty());
+        // nested_func->add_batch_single_place(arguments[0]->size(), get_nested_place(place), arguments_raw.data(), arena);
+        // nested_func->insert_result_into(get_nested_place(place), to, arena);
+
+        nested_func->add_batch_single_place(arguments[0]->size(), get_nested_place(place),
+                                            arguments_raw.data(), nullptr);
+        nested_func->insert_result_into(get_nested_place(place), to);
+    }
+
+    size_t size_of_data() const override { return prefix_size + nested_func->size_of_data(); }
+
+    void create(AggregateDataPtr __restrict place) const override {
+        new (place) Data;
+        nested_func->create(get_nested_place(place));
+    }
+
+    void destroy(AggregateDataPtr __restrict place) const noexcept override {
+        this->data(place).~Data();
+        nested_func->destroy(get_nested_place(place));
+    }
+
+    String get_name() const override { return nested_func->get_name() + "Distinct"; }
+
+    DataTypePtr get_return_type() const override { return nested_func->get_return_type(); }
+
+    bool allocates_memory_in_arena() const override { return true; }
+
+    const char* get_header_file_path() const override { return __FILE__; }
+};
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_hll_union_agg.cpp b/be/src/vec/aggregate_functions/aggregate_function_hll_union_agg.cpp
new file mode 100644
index 0000000..3b2aba0
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_hll_union_agg.cpp
@@ -0,0 +1,51 @@
+// 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.
+
+#include "vec/aggregate_functions/aggregate_function_hll_union_agg.h"
+
+#include "vec/aggregate_functions/aggregate_function_simple_factory.h"
+#include "vec/aggregate_functions/factory_helpers.h"
+
+namespace doris::vectorized {
+
+AggregateFunctionPtr create_aggregate_function_HLL_union_agg(const std::string& name,
+                                                             const DataTypes& argument_types,
+                                                             const Array& parameters,
+                                                             const bool result_is_nullable) {
+    assert_no_parameters(name, parameters);
+    assert_arity_at_most<1>(name, argument_types);
+
+    return std::make_shared<AggregateFunctionHLLUnionAgg>(argument_types);
+}
+
+AggregateFunctionPtr create_aggregate_function_HLL_union(const std::string& name,
+                                                         const DataTypes& argument_types,
+                                                         const Array& parameters,
+                                                         const bool result_is_nullable) {
+    assert_no_parameters(name, parameters);
+    assert_arity_at_most<1>(name, argument_types);
+
+    return std::make_shared<AggregateFunctionHLLUnion>(argument_types);
+}
+
+void register_aggregate_function_HLL_union_agg(AggregateFunctionSimpleFactory& factory) {
+    factory.register_function("hll_union_agg", create_aggregate_function_HLL_union_agg);
+    factory.register_function("hll_union", create_aggregate_function_HLL_union);
+    factory.register_function("hll_raw_agg", create_aggregate_function_HLL_union);
+}
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_hll_union_agg.h b/be/src/vec/aggregate_functions/aggregate_function_hll_union_agg.h
new file mode 100644
index 0000000..f71a1f5
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_hll_union_agg.h
@@ -0,0 +1,133 @@
+// 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 <istream>
+#include <ostream>
+#include <type_traits>
+
+#include "exprs/hll_function.h"
+#include "olap/hll.h"
+#include "util/slice.h"
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/columns/column_string.h"
+#include "vec/columns/column_vector.h"
+#include "vec/data_types/data_type_number.h"
+#include "vec/data_types/data_type_string.h"
+#include "vec/io/io_helper.h"
+
+namespace doris::vectorized {
+
+struct AggregateFunctionHLLData {
+    HyperLogLog dst_hll {};
+
+    void add(const StringRef& src) { dst_hll.merge(HyperLogLog(Slice(src.data, src.size))); }
+
+    void merge(const AggregateFunctionHLLData& rhs) { dst_hll.merge(rhs.dst_hll); }
+
+    void write(BufferWritable& buf) const {
+        std::string result(dst_hll.max_serialized_size(), '0');
+        int size = dst_hll.serialize((uint8_t*)result.c_str());
+        result.resize(size);
+        write_binary(result, buf);
+    }
+
+    void read(BufferReadable& buf) {
+        StringRef ref;
+        read_binary(ref, buf);
+        dst_hll.deserialize(Slice(ref.data, ref.size));
+    }
+
+    Int64 get_cardinality() const { return dst_hll.estimate_cardinality(); }
+
+    std::string get() const {
+        std::string result(dst_hll.max_serialized_size(), '0');
+        int size = dst_hll.serialize((uint8_t*)result.c_str());
+        result.resize(size);
+
+        return result;
+    }
+};
+
+class AggregateFunctionHLLUnionAgg
+        : public IAggregateFunctionDataHelper<AggregateFunctionHLLData,
+                                              AggregateFunctionHLLUnionAgg> {
+public:
+    virtual String get_name() const override { return "hll_union_agg"; }
+
+    AggregateFunctionHLLUnionAgg(const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper(argument_types_, {}) {}
+
+    AggregateFunctionHLLUnionAgg(const IDataType& data_type, const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper(argument_types_, {}) {}
+
+    virtual DataTypePtr get_return_type() const override {
+        return std::make_shared<DataTypeInt64>();
+    }
+
+    void add(AggregateDataPtr __restrict place, const IColumn** columns, size_t row_num,
+             Arena*) const override {
+        const auto& column = static_cast<const ColumnString&>(*columns[0]);
+        this->data(place).add(column.get_data_at(row_num));
+    }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena*) const override {
+        this->data(place).merge(this->data(rhs));
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        this->data(place).write(buf);
+    }
+
+    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, Arena*) const override {
+        this->data(place).read(buf);
+    }
+
+    virtual void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
+        auto& column = static_cast<ColumnVector<Int64>&>(to);
+        column.get_data().push_back(this->data(place).get_cardinality());
+    }
+
+    const char* get_header_file_path() const override { return __FILE__; }
+};
+
+class AggregateFunctionHLLUnion final : public AggregateFunctionHLLUnionAgg {
+public:
+    String get_name() const override { return "hll_union"; }
+
+    AggregateFunctionHLLUnion(const DataTypes& argument_types_)
+            : AggregateFunctionHLLUnionAgg {argument_types_} {}
+
+    AggregateFunctionHLLUnion(const IDataType& data_type, const DataTypes& argument_types_)
+            : AggregateFunctionHLLUnionAgg(data_type, argument_types_) {}
+
+    DataTypePtr get_return_type() const override { return std::make_shared<DataTypeString>(); }
+
+    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
+        auto& column = static_cast<ColumnString&>(to);
+        auto result = this->data(place).get();
+        column.insert_data(result.c_str(), result.length());
+    }
+};
+
+AggregateFunctionPtr create_aggregate_function_HLL_union(const std::string& name,
+                                                         const DataTypes& argument_types,
+                                                         const Array& parameters,
+                                                         const bool result_is_nullable);
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_min_max.cpp b/be/src/vec/aggregate_functions/aggregate_function_min_max.cpp
new file mode 100644
index 0000000..813674a
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_min_max.cpp
@@ -0,0 +1,85 @@
+// 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/AggregateFunctions/AggregateFunctionMinMaxAny.cpp
+// and modified by Doris
+
+#include "vec/aggregate_functions/aggregate_function_min_max.h"
+
+#include "vec/aggregate_functions/aggregate_function_simple_factory.h"
+#include "vec/aggregate_functions/factory_helpers.h"
+#include "vec/aggregate_functions/helpers.h"
+
+namespace doris::vectorized {
+
+/// min, max
+template <template <typename, bool> class AggregateFunctionTemplate, template <typename> class Data>
+static IAggregateFunction* create_aggregate_function_single_value(const String& name,
+                                                                  const DataTypes& argument_types,
+                                                                  const Array& parameters) {
+    assert_no_parameters(name, parameters);
+    assert_unary(name, argument_types);
+
+    const DataTypePtr& argument_type = argument_types[0];
+
+    WhichDataType which(argument_type);
+#define DISPATCH(TYPE)                                                                 \
+    if (which.idx == TypeIndex::TYPE)                                                  \
+        return new AggregateFunctionTemplate<Data<SingleValueDataFixed<TYPE>>, false>( \
+                argument_type);
+    FOR_NUMERIC_TYPES(DISPATCH)
+#undef DISPATCH
+    if (which.idx == TypeIndex::String) {
+        return new AggregateFunctionTemplate<Data<SingleValueDataString>, false>(argument_type);
+    }
+    if (which.idx == TypeIndex::DateTime || which.idx == TypeIndex::Date) {
+        return new AggregateFunctionTemplate<Data<SingleValueDataFixed<Int64>>, false>(
+                argument_type);
+    }
+    if (which.idx == TypeIndex::Decimal128) {
+        return new AggregateFunctionTemplate<Data<SingleValueDataFixed<DecimalV2Value>>, false>(
+                argument_type);
+    }
+    return nullptr;
+}
+
+AggregateFunctionPtr create_aggregate_function_max(const std::string& name,
+                                                   const DataTypes& argument_types,
+                                                   const Array& parameters,
+                                                   const bool result_is_nullable) {
+    return AggregateFunctionPtr(
+            create_aggregate_function_single_value<AggregateFunctionsSingleValue,
+                                                   AggregateFunctionMaxData>(name, argument_types,
+                                                                             parameters));
+}
+
+AggregateFunctionPtr create_aggregate_function_min(const std::string& name,
+                                                   const DataTypes& argument_types,
+                                                   const Array& parameters,
+                                                   const bool result_is_nullable) {
+    return AggregateFunctionPtr(
+            create_aggregate_function_single_value<AggregateFunctionsSingleValue,
+                                                   AggregateFunctionMinData>(name, argument_types,
+                                                                             parameters));
+}
+
+void register_aggregate_function_minmax(AggregateFunctionSimpleFactory& factory) {
+    factory.register_function("max", create_aggregate_function_max);
+    factory.register_function("min", create_aggregate_function_min);
+}
+
+} // namespace doris::vectorized
\ No newline at end of file
diff --git a/be/src/vec/aggregate_functions/aggregate_function_min_max.h b/be/src/vec/aggregate_functions/aggregate_function_min_max.h
new file mode 100644
index 0000000..17d6823
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_min_max.h
@@ -0,0 +1,535 @@
+// 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/AggregateFunctions/AggregateFunctionMinMaxAny.h
+// and modified by Doris
+
+#pragma once
+
+#include "common/logging.h"
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/columns/column_decimal.h"
+#include "vec/columns/column_vector.h"
+#include "vec/common/assert_cast.h"
+#include "vec/io/io_helper.h"
+
+namespace doris::vectorized {
+
+/// For numeric values.
+template <typename T>
+struct SingleValueDataFixed {
+private:
+    using Self = SingleValueDataFixed;
+
+    bool has_value = false; /// We need to remember if at least one value has been passed. This is necessary for AggregateFunctionIf.
+    T value;
+
+public:
+    bool has() const { return has_value; }
+
+    void insert_result_into(IColumn& to) const {
+        if (has())
+            assert_cast<ColumnVector<T>&>(to).get_data().push_back(value);
+        else
+            assert_cast<ColumnVector<T>&>(to).insert_default();
+    }
+
+    void reset() {
+        if (has()) {
+            has_value = false;    
+        }
+    }
+
+    void write(BufferWritable& buf) const {
+        write_binary(has(), buf);
+        if (has()) write_binary(value, buf);
+    }
+
+    void read(BufferReadable& buf) {
+        read_binary(has_value, buf);
+        if (has()) read_binary(value, buf);
+    }
+
+    void change(const IColumn& column, size_t row_num, Arena*) {
+        has_value = true;
+        value = assert_cast<const ColumnVector<T>&>(column).get_data()[row_num];
+    }
+
+    /// Assuming to.has()
+    void change(const Self& to, Arena*) {
+        has_value = true;
+        value = to.value;
+    }
+
+    bool change_first_time(const IColumn& column, size_t row_num, Arena* arena) {
+        if (!has()) {
+            change(column, row_num, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_first_time(const Self& to, Arena* arena) {
+        if (!has() && to.has()) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_every_time(const IColumn& column, size_t row_num, Arena* arena) {
+        change(column, row_num, arena);
+        return true;
+    }
+
+    bool change_every_time(const Self& to, Arena* arena) {
+        if (to.has()) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_less(const IColumn& column, size_t row_num, Arena* arena) {
+        if (!has() || assert_cast<const ColumnVector<T>&>(column).get_data()[row_num] < value) {
+            change(column, row_num, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_less(const Self& to, Arena* arena) {
+        if (to.has() && (!has() || to.value < value)) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_greater(const IColumn& column, size_t row_num, Arena* arena) {
+        if (!has() || assert_cast<const ColumnVector<T>&>(column).get_data()[row_num] > value) {
+            change(column, row_num, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_greater(const Self& to, Arena* arena) {
+        if (to.has() && (!has() || to.value > value)) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool is_equal_to(const Self& to) const { return has() && to.value == value; }
+
+    bool is_equal_to(const IColumn& column, size_t row_num) const {
+        return has() && assert_cast<const ColumnVector<T>&>(column).get_data()[row_num] == value;
+    }
+};
+
+/// For numeric values.
+template <>
+struct SingleValueDataFixed<DecimalV2Value> {
+private:
+    using Self = SingleValueDataFixed;
+
+    bool has_value =
+            false; /// We need to remember if at least one value has been passed. This is necessary for AggregateFunctionIf.
+    int128_t value;
+
+public:
+    bool has() const { return has_value; }
+
+    void insert_result_into(IColumn& to) const {
+        if (has()) {
+            DecimalV2Value decimal(value);
+            assert_cast<ColumnDecimal<Decimal128>&>(to).insert_data((const char*)&decimal, 0);
+        } else
+            assert_cast<ColumnDecimal<Decimal128>&>(to).insert_default();
+    }
+
+    void reset() {
+        if (has()) {
+            has_value = false;    
+        }
+    }
+    
+    void write(BufferWritable& buf) const {
+        write_binary(has(), buf);
+        if (has()) write_binary(value, buf);
+    }
+
+    void read(BufferReadable& buf) {
+        read_binary(has_value, buf);
+        if (has()) read_binary(value, buf);
+    }
+
+    void change(const IColumn& column, size_t row_num, Arena*) {
+        has_value = true;
+        value = assert_cast<const ColumnDecimal<Decimal128>&>(column).get_data()[row_num];
+    }
+
+    /// Assuming to.has()
+    void change(const Self& to, Arena*) {
+        has_value = true;
+        value = to.value;
+    }
+
+    bool change_first_time(const IColumn& column, size_t row_num, Arena* arena) {
+        if (!has()) {
+            change(column, row_num, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_first_time(const Self& to, Arena* arena) {
+        if (!has() && to.has()) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_every_time(const IColumn& column, size_t row_num, Arena* arena) {
+        change(column, row_num, arena);
+        return true;
+    }
+
+    bool change_every_time(const Self& to, Arena* arena) {
+        if (to.has()) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_less(const IColumn& column, size_t row_num, Arena* arena) {
+        if (!has() ||
+            assert_cast<const ColumnDecimal<Decimal128>&>(column).get_data()[row_num] < value) {
+            change(column, row_num, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_less(const Self& to, Arena* arena) {
+        if (to.has() && (!has() || to.value < value)) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_greater(const IColumn& column, size_t row_num, Arena* arena) {
+        if (!has() ||
+            assert_cast<const ColumnDecimal<Decimal128>&>(column).get_data()[row_num] > value) {
+            change(column, row_num, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_greater(const Self& to, Arena* arena) {
+        if (to.has() && (!has() || to.value > value)) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool is_equal_to(const Self& to) const { return has() && to.value == value; }
+
+    bool is_equal_to(const IColumn& column, size_t row_num) const {
+        return has() &&
+               assert_cast<const ColumnDecimal<Decimal128>&>(column).get_data()[row_num] == value;
+    }
+};
+
+/** For strings. Short strings are stored in the object itself, and long strings are allocated separately.
+  * NOTE It could also be suitable for arrays of numbers.
+  */
+struct SingleValueDataString {
+private:
+    using Self = SingleValueDataString;
+
+    Int32 size = -1;    /// -1 indicates that there is no value.
+    Int32 capacity = 0; /// power of two or zero
+    char* large_data = nullptr;
+
+public:
+    static constexpr Int32 AUTOMATIC_STORAGE_SIZE = 64;
+    static constexpr Int32 MAX_SMALL_STRING_SIZE =
+            AUTOMATIC_STORAGE_SIZE - sizeof(size) - sizeof(capacity) - sizeof(large_data);
+
+private:
+    char small_data[MAX_SMALL_STRING_SIZE]; /// Including the terminating zero.
+
+public:
+    ~SingleValueDataString() { delete large_data; }
+
+    bool has() const { return size >= 0; }
+
+    const char* get_data() const { return size <= MAX_SMALL_STRING_SIZE ? small_data : large_data; }
+
+    void insert_result_into(IColumn& to) const {
+        if (has())
+            assert_cast<ColumnString&>(to).insert_data(get_data(), size);
+        else
+            assert_cast<ColumnString&>(to).insert_default();
+    }
+
+    void reset() {
+        if (size != -1) {
+            size = -1;    
+            capacity = 0; 
+            delete large_data;
+            large_data = nullptr;
+        }
+    }
+    
+    void write(BufferWritable& buf) const {
+        write_binary(size, buf);
+        if (has()) buf.write(get_data(), size);
+    }
+
+    void read(BufferReadable& buf) {
+        Int32 rhs_size;
+        read_binary(rhs_size, buf);
+
+        if (rhs_size >= 0) {
+            if (rhs_size <= MAX_SMALL_STRING_SIZE) {
+                /// Don't free large_data here.
+
+                size = rhs_size;
+
+                if (size > 0) buf.read(small_data, size);
+            } else {
+                if (capacity < rhs_size) {
+                    capacity = static_cast<UInt32>(round_up_to_power_of_two_or_zero(rhs_size));
+                    delete large_data;
+                    large_data = new char[capacity];
+                }
+
+                size = rhs_size;
+                buf.read(large_data, size);
+            }
+        } else {
+            /// Don't free large_data here.
+            size = rhs_size;
+        }
+    }
+
+    StringRef get_string_ref() const { return StringRef(get_data(), size); }
+
+    /// Assuming to.has()
+    void change_impl(StringRef value, Arena* arena) {
+        Int32 value_size = value.size;
+
+        if (value_size <= MAX_SMALL_STRING_SIZE) {
+            /// Don't free large_data here.
+            size = value_size;
+
+            if (size > 0) {
+                memcpy(small_data, value.data, size);
+            }
+        } else {
+            if (capacity < value_size) {
+                /// Don't free large_data here.
+                capacity = round_up_to_power_of_two_or_zero(value_size);
+                delete large_data;
+                large_data = new char[capacity];
+            }
+
+            size = value_size;
+            memcpy(large_data, value.data, size);
+        }
+    }
+
+    void change(const IColumn& column, size_t row_num, Arena* arena) {
+        change_impl(assert_cast<const ColumnString&>(column).get_data_at(row_num), arena);
+    }
+
+    void change(const Self& to, Arena* arena) { change_impl(to.get_string_ref(), arena); }
+
+    bool change_if_less(const IColumn& column, size_t row_num, Arena* arena) {
+        if (!has() ||
+            assert_cast<const ColumnString&>(column).get_data_at(row_num) < get_string_ref()) {
+            change(column, row_num, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_greater(const IColumn& column, size_t row_num, Arena* arena) {
+        if (!has() ||
+            assert_cast<const ColumnString&>(column).get_data_at(row_num) > get_string_ref()) {
+            change(column, row_num, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_first_time(const IColumn& column, size_t row_num, Arena* arena) {
+        if (!has()) {
+            change(column, row_num, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_first_time(const Self& to, Arena* arena) {
+        if (!has() && to.has()) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_every_time(const IColumn& column, size_t row_num, Arena* arena) {
+        change(column, row_num, arena);
+        return true;
+    }
+
+    bool change_every_time(const Self& to, Arena* arena) {
+        if (to.has()) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_less(const Self& to, Arena* arena) {
+        if (to.has() && (!has() || to.get_string_ref() < get_string_ref())) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool change_if_greater(const Self& to, Arena* arena) {
+        if (to.has() && (!has() || to.get_string_ref() > get_string_ref())) {
+            change(to, arena);
+            return true;
+        } else
+            return false;
+    }
+
+    bool is_equal_to(const Self& to) const {
+        return has() && to.get_string_ref() == get_string_ref();
+    }
+
+    bool is_equal_to(const IColumn& column, size_t row_num) const { return false; }
+};
+
+template <typename Data>
+struct AggregateFunctionMaxData : Data {
+    using Self = AggregateFunctionMaxData;
+
+    bool change_if_better(const IColumn& column, size_t row_num, Arena* arena) {
+        return this->change_if_greater(column, row_num, arena);
+    }
+    bool change_if_better(const Self& to, Arena* arena) {
+        return this->change_if_greater(to, arena);
+    }
+
+    static const char* name() { return "max"; }
+};
+
+template <typename Data>
+struct AggregateFunctionMinData : Data {
+    using Self = AggregateFunctionMinData;
+
+    bool change_if_better(const IColumn& column, size_t row_num, Arena* arena) {
+        return this->change_if_less(column, row_num, arena);
+    }
+    bool change_if_better(const Self& to, Arena* arena) { return this->change_if_less(to, arena); }
+
+    static const char* name() { return "min"; }
+};
+
+template <typename Data, bool AllocatesMemoryInArena>
+class AggregateFunctionsSingleValue final
+        : public IAggregateFunctionDataHelper<
+                  Data, AggregateFunctionsSingleValue<Data, AllocatesMemoryInArena>> {
+private:
+    DataTypePtr& type;
+
+public:
+    AggregateFunctionsSingleValue(const DataTypePtr& type_)
+            : IAggregateFunctionDataHelper<
+                      Data, AggregateFunctionsSingleValue<Data, AllocatesMemoryInArena>>({type_},
+                                                                                         {}),
+              type(this->argument_types[0]) {
+        if (StringRef(Data::name()) == StringRef("min") ||
+            StringRef(Data::name()) == StringRef("max")) {
+            if (!type->is_comparable()) {
+                LOG(FATAL) << fmt::format(
+                        "Illegal type {} of argument of aggregate function {} because the values "
+                        "of that data type are not comparable",
+                        type->get_name(), get_name());
+            }
+        }
+    }
+
+    String get_name() const override { return Data::name(); }
+
+    DataTypePtr get_return_type() const override { return type; }
+
+    void add(AggregateDataPtr __restrict place, const IColumn** columns, size_t row_num,
+             Arena* arena) const override {
+        this->data(place).change_if_better(*columns[0], row_num, arena);
+    }
+
+    void reset(AggregateDataPtr place) const override {
+        this->data(place).reset();
+    }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena* arena) const override {
+        this->data(place).change_if_better(this->data(rhs), arena);
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        this->data(place).write(buf);
+    }
+
+    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, Arena*) const override {
+        this->data(place).read(buf);
+    }
+
+    bool allocates_memory_in_arena() const override { return AllocatesMemoryInArena; }
+
+    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
+        this->data(place).insert_result_into(to);
+    }
+
+    const char* get_header_file_path() const override { return __FILE__; }
+};
+
+AggregateFunctionPtr create_aggregate_function_max(const std::string& name,
+                                                   const DataTypes& argument_types,
+                                                   const Array& parameters,
+                                                   const bool result_is_nullable);
+
+AggregateFunctionPtr create_aggregate_function_min(const std::string& name,
+                                                   const DataTypes& argument_types,
+                                                   const Array& parameters,
+                                                   const bool result_is_nullable);
+
+} // namespace doris::vectorized
\ No newline at end of file
diff --git a/be/src/vec/aggregate_functions/aggregate_function_nothing.h b/be/src/vec/aggregate_functions/aggregate_function_nothing.h
new file mode 100644
index 0000000..4c7b193
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_nothing.h
@@ -0,0 +1,71 @@
+// 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/AggregateFunctions/AggregateFunctionNothing.h
+// and modified by Doris
+
+#pragma once
+
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/columns/column.h"
+#include "vec/data_types/data_type_nothing.h"
+#include "vec/data_types/data_type_nullable.h"
+#include "vec/io/io_helper.h"
+
+namespace doris::vectorized {
+
+/** Aggregate function that takes arbitrary number of arbitrary arguments and does nothing.
+  */
+class AggregateFunctionNothing final : public IAggregateFunctionHelper<AggregateFunctionNothing> {
+public:
+    AggregateFunctionNothing(const DataTypes& arguments, const Array& params)
+            : IAggregateFunctionHelper<AggregateFunctionNothing>(arguments, params) {}
+
+    String get_name() const override { return "nothing"; }
+
+    DataTypePtr get_return_type() const override {
+        return std::make_shared<DataTypeNullable>(std::make_shared<DataTypeNothing>());
+    }
+
+    void create(AggregateDataPtr) const override {}
+
+    void destroy(AggregateDataPtr) const noexcept override {}
+
+    bool has_trivial_destructor() const override { return true; }
+
+    size_t size_of_data() const override { return 0; }
+
+    size_t align_of_data() const override { return 1; }
+
+    void add(AggregateDataPtr, const IColumn**, size_t, Arena*) const override {}
+
+    void reset(AggregateDataPtr place) const override {}
+    
+    void merge(AggregateDataPtr, ConstAggregateDataPtr, Arena*) const override {}
+
+    void serialize(ConstAggregateDataPtr, BufferWritable& buf) const override {}
+
+    void deserialize(AggregateDataPtr, BufferReadable& buf, Arena*) const override {}
+
+    void insert_result_into(ConstAggregateDataPtr, IColumn& to) const override {
+        to.insert_default();
+    }
+
+    const char* get_header_file_path() const override { return __FILE__; }
+};
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_null.cpp b/be/src/vec/aggregate_functions/aggregate_function_null.cpp
new file mode 100644
index 0000000..e28287f
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_null.cpp
@@ -0,0 +1,92 @@
+// 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/AggregateFunctions/AggregateFunctionNull.cpp
+// and modified by Doris
+
+#include "vec/aggregate_functions/aggregate_function_null.h"
+
+#include "common/logging.h"
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/aggregate_functions/aggregate_function_combinator.h"
+#include "vec/aggregate_functions/aggregate_function_count.h"
+#include "vec/aggregate_functions/aggregate_function_nothing.h"
+#include "vec/aggregate_functions/aggregate_function_simple_factory.h"
+#include "vec/data_types/data_type_nullable.h"
+
+namespace doris::vectorized {
+
+class AggregateFunctionCombinatorNull final : public IAggregateFunctionCombinator {
+public:
+    String get_name() const override { return "Null"; }
+
+    bool is_for_internal_usage_only() const override { return true; }
+
+    DataTypes transform_arguments(const DataTypes& arguments) const override {
+        size_t size = arguments.size();
+        DataTypes res(size);
+        for (size_t i = 0; i < size; ++i) res[i] = remove_nullable(arguments[i]);
+        return res;
+    }
+
+    AggregateFunctionPtr transform_aggregate_function(const AggregateFunctionPtr& nested_function,
+                                                      const DataTypes& arguments,
+                                                      const Array& params,
+                                                      const bool result_is_nullable) const override {
+        if (nested_function == nullptr) return nullptr;
+
+        bool has_null_types = false;
+        for (const auto& arg_type : arguments) {
+            if (arg_type->only_null()) {
+                has_null_types = true;
+                break;
+            }
+        }
+
+        if (has_null_types) return std::make_shared<AggregateFunctionNothing>(arguments, params);
+
+        if (arguments.size() == 1) {
+            if (result_is_nullable)
+                return std::make_shared<AggregateFunctionNullUnary<true>>(nested_function,
+                                                                          arguments, params);
+            else
+                return std::make_shared<AggregateFunctionNullUnary<false>>(nested_function,
+                                                                           arguments, params);
+        } else {
+            if (result_is_nullable)
+                return std::make_shared<AggregateFunctionNullVariadic<true>>(nested_function,
+                                                                             arguments, params);
+            else
+                return std::make_shared<AggregateFunctionNullVariadic<false>>(nested_function,
+                                                                              arguments, params);
+        }
+    }
+};
+
+void register_aggregate_function_combinator_null(AggregateFunctionSimpleFactory& factory) {
+    // factory.registerCombinator(std::make_shared<AggregateFunctionCombinatorNull>());
+    AggregateFunctionCreator creator = [&](const std::string& name, const DataTypes& types,
+                                           const Array& params, const bool result_is_nullable) {
+        auto function_combinator = std::make_shared<AggregateFunctionCombinatorNull>();
+        auto transform_arguments = function_combinator->transform_arguments(types);
+        auto nested_function = factory.get(name, transform_arguments, params);
+        return function_combinator->transform_aggregate_function(nested_function, types, params, result_is_nullable);
+    };
+    factory.register_nullable_function_combinator(creator);
+}
+
+} // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_null.h b/be/src/vec/aggregate_functions/aggregate_function_null.h
new file mode 100644
index 0000000..9458d7d
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_null.h
@@ -0,0 +1,294 @@
+// 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/AggregateFunctions/AggregateFunctionNull.h
+// and modified by Doris
+
+#pragma once
+
+#include <array>
+
+#include "common/logging.h"
+#include "common/status.h"
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/common/assert_cast.h"
+#include "vec/data_types/data_type_nullable.h"
+#include "vec/io/io_helper.h"
+
+namespace doris::vectorized {
+
+/// This class implements a wrapper around an aggregate function. Despite its name,
+/// this is an adapter. It is used to handle aggregate functions that are called with
+/// at least one nullable argument. It implements the logic according to which any
+/// row that contains at least one NULL is skipped.
+
+/// If all rows had NULL, the behaviour is determined by "result_is_nullable" template parameter.
+///  true - return NULL; false - return value from empty aggregation state of nested function.
+
+template <bool result_is_nullable, typename Derived>
+class AggregateFunctionNullBase : public IAggregateFunctionHelper<Derived> {
+protected:
+    AggregateFunctionPtr nested_function;
+    size_t prefix_size;
+
+    /** In addition to data for nested aggregate function, we keep a flag
+      *  indicating - was there at least one non-NULL value accumulated.
+      * In case of no not-NULL values, the function will return NULL.
+      *
+      * We use prefix_size bytes for flag to satisfy the alignment requirement of nested state.
+      */
+
+    AggregateDataPtr nested_place(AggregateDataPtr __restrict place) const noexcept {
+        return place + prefix_size;
+    }
+
+    ConstAggregateDataPtr nested_place(ConstAggregateDataPtr __restrict place) const noexcept {
+        return place + prefix_size;
+    }
+
+    static void init_flag(AggregateDataPtr __restrict place) noexcept {
+        if constexpr (result_is_nullable)
+            place[0] = 0;
+    }
+
+    static void set_flag(AggregateDataPtr __restrict place) noexcept {
+        if constexpr (result_is_nullable)
+            place[0] = 1;
+    }
+
+    static bool get_flag(ConstAggregateDataPtr __restrict place) noexcept {
+        return result_is_nullable ? place[0] : 1;
+    }
+
+public:
+    AggregateFunctionNullBase(AggregateFunctionPtr nested_function_, const DataTypes& arguments,
+                              const Array& params)
+            : IAggregateFunctionHelper<Derived>(arguments, params),
+              nested_function {nested_function_} {
+        if (result_is_nullable)
+            prefix_size = nested_function->align_of_data();
+        else
+            prefix_size = 0;
+    }
+
+    String get_name() const override {
+        /// This is just a wrapper. The function for Nullable arguments is named the same as the nested function itself.
+        return nested_function->get_name();
+    }
+
+    DataTypePtr get_return_type() const override {
+        return result_is_nullable ? make_nullable(nested_function->get_return_type())
+                                  : nested_function->get_return_type();
+    }
+
+    void create(AggregateDataPtr __restrict place) const override {
+        init_flag(place);
+        nested_function->create(nested_place(place));
+    }
+
+    void destroy(AggregateDataPtr __restrict place) const noexcept override {
+        nested_function->destroy(nested_place(place));
+    }
+    void reset(AggregateDataPtr place) const override {
+        init_flag(place);
+        nested_function->reset(nested_place(place));
+    }
+
+    bool has_trivial_destructor() const override {
+        return nested_function->has_trivial_destructor();
+    }
+
+    size_t size_of_data() const override { return prefix_size + nested_function->size_of_data(); }
+
+    size_t align_of_data() const override { return nested_function->align_of_data(); }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena* arena) const override {
+        if (result_is_nullable && get_flag(rhs)) set_flag(place);
+
+        nested_function->merge(nested_place(place), nested_place(rhs), arena);
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        bool flag = get_flag(place);
+        if (result_is_nullable) write_binary(flag, buf);
+        if (flag) {
+            nested_function->serialize(nested_place(place), buf);
+        }
+    }
... 66417 lines suppressed ...

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