HappenLee commented on code in PR #59830: URL: https://github.com/apache/doris/pull/59830#discussion_r2726928601
########## be/src/vec/exprs/short_circuit_util.h: ########## @@ -0,0 +1,499 @@ +// 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 "vec/columns/column.h" +#include "vec/columns/column_const.h" +#include "vec/columns/column_nullable.h" +#include "vec/columns/column_vector.h" +#include "vec/core/column_with_type_and_name.h" +#include "vec/core/field.h" +#include "vec/exprs/vexpr.h" + +namespace doris::vectorized { + +// Used to store a column along with its null_map and whether it is a const column. +// If the input column is not nullable, then null_map will be nullptr. +struct ColumnNullConstView { + const IColumn& column; + const NullMap* null_map; + const bool is_const; + + static ColumnNullConstView create(const ColumnPtr& column_ptr) { + const auto& [from_data_column, is_const] = unpack_if_const(column_ptr); + + if (const auto* nullable_column = + check_and_get_column<ColumnNullable>(from_data_column.get())) { + return ColumnNullConstView {.column = nullable_column->get_nested_column(), + .null_map = &nullable_column->get_null_map_data(), + .is_const = is_const}; + } else { + return ColumnNullConstView { + .column = *from_data_column, .null_map = nullptr, .is_const = is_const}; + } + } +}; + +// Scalar version stores a reference to the actual data type array for convenient subsequent operations. +template <PrimitiveType PType> +struct ColumnNullConstViewScalar { + using ColumnType = typename PrimitiveTypeTraits<PType>::ColumnType; + using ArrayType = typename ColumnType::Container; + + const ArrayType& data; + const NullMap* null_map; + const bool is_const; + + static ColumnNullConstViewScalar create(const ColumnPtr& column_ptr) { + const auto& [from_data_column, is_const] = unpack_if_const(column_ptr); + const NullMap* null_map = nullptr; + const ArrayType* data = nullptr; + if (const auto* nullable_column = + check_and_get_column<ColumnNullable>(from_data_column.get())) { + null_map = &nullable_column->get_null_map_data(); + const auto& nested_from_column = nullable_column->get_nested_column(); + data = &(assert_cast<const ColumnType&>(nested_from_column).get_data()); + } else { + data = &(assert_cast<const ColumnType&>(*from_data_column).get_data()); + } + + return ColumnNullConstViewScalar { + .data = *data, .null_map = null_map, .is_const = is_const}; + } +}; + +// Used to store a mutable column along with its null_map. +// If the input column is not nullable, then null_map will be nullptr. +struct MutableColumnNullView { + IColumn& column; + NullMap* null_map; + static MutableColumnNullView create(const MutableColumnPtr& column_ptr) { + if (auto* nullable_column = check_and_get_column<ColumnNullable>(column_ptr.get())) { + return MutableColumnNullView {.column = nullable_column->get_nested_column(), + .null_map = &nullable_column->get_null_map_data()}; + } else { + return MutableColumnNullView {.column = *column_ptr, .null_map = nullptr}; + } + } + + void insert_from(const ColumnNullConstView& from, size_t i) { + auto index = index_check_const(i, from.is_const); + column.insert_from(from.column, index); + if (null_map != nullptr && from.null_map != nullptr) { + null_map->push_back((*from.null_map)[index]); + } else if (null_map != nullptr) { + // from is not nullable, so insert 0 + null_map->push_back(0); + } + } + + void insert_null() { + if (null_map == nullptr) { + throw doris::Exception(ErrorCode::INTERNAL_ERROR, + "Cannot insert null value into non-nullable column in " + "ShortCircuitCoalesceExpr."); + } + column.insert_default(); + null_map->push_back(1); + } +}; + +template <PrimitiveType PType> +struct MutableColumnNullViewScalar { + using ColumnType = typename PrimitiveTypeTraits<PType>::ColumnType; + using ArrayType = typename ColumnType::Container; + + ArrayType& data; + NullMap* null_map; + + static MutableColumnNullViewScalar create(const MutableColumnPtr& column_ptr) { + ColumnType* data_column = nullptr; + NullMap* null_map = nullptr; + if (auto* nullable_column = check_and_get_column<ColumnNullable>(column_ptr.get())) { + null_map = &nullable_column->get_null_map_data(); + auto& nested_column = nullable_column->get_nested_column(); + data_column = &(assert_cast<ColumnType&>(nested_column)); + } else { + data_column = assert_cast<ColumnType*>(column_ptr.get()); + } + + return MutableColumnNullViewScalar {.data = data_column->get_data(), .null_map = null_map}; + } + + void insert_from(const ColumnNullConstViewScalar<PType>& from, const Selector& selector) { + auto& result_data = data; + const auto& from_data = from.data; + + auto* result_null_map_data = null_map; + const auto* from_null_map_data = from.null_map; + + if (from.is_const) { + insert_into_result<true>(result_data, from_data, result_null_map_data, + from_null_map_data, selector); + } else { + insert_into_result<false>(result_data, from_data, result_null_map_data, + from_null_map_data, selector); + } + } + + template <bool is_const> + static void insert_into_result(ArrayType& result_data, const ArrayType& from_data, + NullMap* result_null_map_data, const NullMap* from_null_map_data, + const Selector& selector) { + insert_with_selector<is_const>(result_data, from_data, selector); + if (result_null_map_data != nullptr && from_null_map_data != nullptr) { + insert_with_selector<is_const>(*result_null_map_data, *from_null_map_data, selector); + } + // Note: When from_null_map_data is nullptr (non-nullable source), + // no action needed since result null_map is already initialized to 0 (non-null) + // by init_result_column's resize_fill(count, 0) + } + + template <bool is_const> + static void insert_with_selector(auto& result_data, const auto& data, + const Selector& selector) { + for (size_t i = 0; i < selector.size(); ++i) { + auto index = selector[i]; + result_data[index] = data[index_check_const<is_const>(i)]; + } + } + + void insert_null(const Selector& selector) { + if (selector.empty()) { Review Comment: like `insert_with_selector` seems no need to check the selector.empty() , for loop is enough -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
