blob: 08ce48da918cdb9c26735320e2e8ee6325b6bd22 [file]
// 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 "exprs/short_circuit_util.h"
#include <gtest/gtest.h>
#include "core/column/column.h"
#include "core/column/column_const.h"
#include "core/column/column_string.h"
#include "core/data_type/data_type_nullable.h"
#include "core/data_type/data_type_number.h"
#include "core/data_type/data_type_string.h"
#include "core/data_type/primitive_type.h"
#include "testutil/column_helper.h"
namespace doris {
// ==================== ColumnNullConstView Tests ====================
TEST(ShortCircuitUtilTest, ColumnNullConstView_non_nullable) {
auto col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
auto view = ColumnNullConstView::create(col);
EXPECT_EQ(view.column.size(), 3);
EXPECT_EQ(view.null_map, nullptr);
EXPECT_FALSE(view.is_const);
}
TEST(ShortCircuitUtilTest, ColumnNullConstView_nullable) {
auto col = ColumnHelper::create_nullable_column<DataTypeInt32>({1, 2, 3}, {0, 1, 0});
auto view = ColumnNullConstView::create(col);
EXPECT_EQ(view.column.size(), 3);
EXPECT_NE(view.null_map, nullptr);
EXPECT_EQ((*view.null_map)[0], 0);
EXPECT_EQ((*view.null_map)[1], 1);
EXPECT_EQ((*view.null_map)[2], 0);
EXPECT_FALSE(view.is_const);
}
TEST(ShortCircuitUtilTest, ColumnNullConstView_const_column) {
auto col = ColumnHelper::create_column<DataTypeInt32>({42});
ColumnPtr const_col = ColumnConst::create(col, 5);
auto view = ColumnNullConstView::create(const_col);
EXPECT_EQ(view.column.size(), 1);
EXPECT_EQ(view.null_map, nullptr);
EXPECT_TRUE(view.is_const);
}
TEST(ShortCircuitUtilTest, ColumnNullConstView_const_nullable_column) {
auto col = ColumnHelper::create_nullable_column<DataTypeInt32>({42}, {0});
ColumnPtr const_col = ColumnConst::create(col, 5);
auto view = ColumnNullConstView::create(const_col);
EXPECT_EQ(view.column.size(), 1);
EXPECT_NE(view.null_map, nullptr);
EXPECT_TRUE(view.is_const);
}
// ==================== ColumnNullConstViewScalar Tests ====================
TEST(ShortCircuitUtilTest, ColumnNullConstViewScalar_non_nullable) {
auto col = ColumnHelper::create_column<DataTypeInt32>({10, 20, 30});
auto view = ColumnNullConstViewScalar<TYPE_INT>::create(col);
EXPECT_EQ(view.data.size(), 3);
EXPECT_EQ(view.data[0], 10);
EXPECT_EQ(view.data[1], 20);
EXPECT_EQ(view.data[2], 30);
EXPECT_EQ(view.null_map, nullptr);
EXPECT_FALSE(view.is_const);
}
TEST(ShortCircuitUtilTest, ColumnNullConstViewScalar_nullable) {
auto col = ColumnHelper::create_nullable_column<DataTypeInt32>({10, 20, 30}, {0, 1, 0});
auto view = ColumnNullConstViewScalar<TYPE_INT>::create(col);
EXPECT_EQ(view.data.size(), 3);
EXPECT_EQ(view.data[0], 10);
EXPECT_EQ(view.data[2], 30);
EXPECT_NE(view.null_map, nullptr);
EXPECT_EQ((*view.null_map)[1], 1);
EXPECT_FALSE(view.is_const);
}
// ==================== MutableColumnNullView Tests ====================
TEST(ShortCircuitUtilTest, MutableColumnNullView_insert_from_non_nullable) {
auto src_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
auto src_view = ColumnNullConstView::create(src_col);
MutableColumnPtr dst_col = ColumnInt32::create();
auto dst_view = MutableColumnNullView::create(dst_col);
dst_view.insert_from(src_view, 0);
dst_view.insert_from(src_view, 1);
dst_view.insert_from(src_view, 2);
EXPECT_EQ(dst_col->size(), 3);
EXPECT_EQ(dst_col->get_int(0), 1);
EXPECT_EQ(dst_col->get_int(1), 2);
EXPECT_EQ(dst_col->get_int(2), 3);
}
TEST(ShortCircuitUtilTest, MutableColumnNullView_insert_from_nullable_to_nullable) {
auto src_col = ColumnHelper::create_nullable_column<DataTypeInt32>({1, 2, 3}, {0, 1, 0});
auto src_view = ColumnNullConstView::create(src_col);
auto nested_col = ColumnInt32::create();
auto null_map = ColumnUInt8::create();
MutableColumnPtr dst_col = ColumnNullable::create(std::move(nested_col), std::move(null_map));
auto dst_view = MutableColumnNullView::create(dst_col);
dst_view.insert_from(src_view, 0);
dst_view.insert_from(src_view, 1);
dst_view.insert_from(src_view, 2);
EXPECT_EQ(dst_col->size(), 3);
EXPECT_FALSE(dst_col->is_null_at(0));
EXPECT_TRUE(dst_col->is_null_at(1));
EXPECT_FALSE(dst_col->is_null_at(2));
}
TEST(ShortCircuitUtilTest, MutableColumnNullView_insert_null) {
auto nested_col = ColumnInt32::create();
auto null_map = ColumnUInt8::create();
MutableColumnPtr dst_col = ColumnNullable::create(std::move(nested_col), std::move(null_map));
auto dst_view = MutableColumnNullView::create(dst_col);
dst_view.insert_null();
dst_view.insert_null();
EXPECT_EQ(dst_col->size(), 2);
EXPECT_TRUE(dst_col->is_null_at(0));
EXPECT_TRUE(dst_col->is_null_at(1));
}
// ==================== MutableColumnNullViewScalar Tests ====================
TEST(ShortCircuitUtilTest, MutableColumnNullViewScalar_insert_from) {
auto src_col = ColumnHelper::create_column<DataTypeInt32>({100, 200, 300});
auto src_view = ColumnNullConstViewScalar<TYPE_INT>::create(src_col);
MutableColumnPtr dst_col = ColumnInt32::create();
assert_cast<ColumnInt32*>(dst_col.get())->get_data().resize(5);
auto dst_view = MutableColumnNullViewScalar<TYPE_INT>::create(dst_col);
// Use selector to specify insert positions
Selector selector = {0, 2, 4};
dst_view.insert_from(src_view, selector);
EXPECT_EQ(dst_view.data[0], 100);
EXPECT_EQ(dst_view.data[2], 200);
EXPECT_EQ(dst_view.data[4], 300);
}
TEST(ShortCircuitUtilTest, MutableColumnNullViewScalar_insert_from_const) {
auto src_col = ColumnHelper::create_column<DataTypeInt32>({42});
ColumnPtr const_col = ColumnConst::create(src_col, 3);
auto src_view = ColumnNullConstViewScalar<TYPE_INT>::create(const_col);
EXPECT_TRUE(src_view.is_const);
MutableColumnPtr dst_col = ColumnInt32::create();
assert_cast<ColumnInt32*>(dst_col.get())->get_data().resize(3);
auto dst_view = MutableColumnNullViewScalar<TYPE_INT>::create(dst_col);
Selector selector = {0, 1, 2};
dst_view.insert_from(src_view, selector);
// All positions should have the constant value 42
EXPECT_EQ(dst_view.data[0], 42);
EXPECT_EQ(dst_view.data[1], 42);
EXPECT_EQ(dst_view.data[2], 42);
}
TEST(ShortCircuitUtilTest, MutableColumnNullViewScalar_insert_null) {
auto nested_col = ColumnInt32::create();
auto null_map = ColumnUInt8::create();
MutableColumnPtr dst_col = ColumnNullable::create(std::move(nested_col), std::move(null_map));
// Resize first
auto* nullable_col = assert_cast<ColumnNullable*>(dst_col.get());
nullable_col->get_nested_column().resize(5);
nullable_col->get_null_map_data().resize_fill(5, 0);
auto dst_view = MutableColumnNullViewScalar<TYPE_INT>::create(dst_col);
Selector null_selector = {1, 3};
dst_view.insert_null(null_selector);
EXPECT_EQ((*dst_view.null_map)[0], 0);
EXPECT_EQ((*dst_view.null_map)[1], 1);
EXPECT_EQ((*dst_view.null_map)[2], 0);
EXPECT_EQ((*dst_view.null_map)[3], 1);
EXPECT_EQ((*dst_view.null_map)[4], 0);
}
TEST(ShortCircuitUtilTest, MutableColumnNullViewScalar_insert_null_empty_selector) {
auto nested_col = ColumnInt32::create();
auto null_map = ColumnUInt8::create();
MutableColumnPtr dst_col = ColumnNullable::create(std::move(nested_col), std::move(null_map));
auto* nullable_col = assert_cast<ColumnNullable*>(dst_col.get());
nullable_col->get_nested_column().resize(3);
nullable_col->get_null_map_data().resize_fill(3, 0);
auto dst_view = MutableColumnNullViewScalar<TYPE_INT>::create(dst_col);
Selector empty_selector = {};
dst_view.insert_null(empty_selector); // Should not crash
// null_map should remain unchanged
EXPECT_EQ((*dst_view.null_map)[0], 0);
EXPECT_EQ((*dst_view.null_map)[1], 0);
EXPECT_EQ((*dst_view.null_map)[2], 0);
}
// ==================== ColumnAndSelector Tests ====================
TEST(ShortCircuitUtilTest, ColumnAndSelector_output_nulls) {
{
ColumnAndSelector cs;
cs.column = nullptr;
EXPECT_TRUE(cs.output_nulls());
}
{
ColumnAndSelector cs;
cs.column = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
EXPECT_FALSE(cs.output_nulls());
}
}
TEST(ShortCircuitUtilTest, ColumnAndSelector_debug_string) {
// Test with null column
{
ColumnAndSelector cs;
cs.column = nullptr;
cs.selector = {0, 1, 2};
std::string debug_str = cs.debug_string();
EXPECT_NE(debug_str.find("selector_size=3"), std::string::npos);
EXPECT_NE(debug_str.find("output_nulls=1"), std::string::npos);
EXPECT_NE(debug_str.find("column size=null"), std::string::npos);
}
// Test with non-null column
{
ColumnAndSelector cs;
cs.column = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3, 4, 5});
cs.selector = {0, 2};
std::string debug_str = cs.debug_string();
EXPECT_NE(debug_str.find("selector_size=2"), std::string::npos);
EXPECT_NE(debug_str.find("output_nulls=0"), std::string::npos);
EXPECT_NE(debug_str.find("column size=5"), std::string::npos);
}
// Test with empty selector
{
ColumnAndSelector cs;
cs.column = ColumnHelper::create_column<DataTypeInt32>({1});
cs.selector = {};
std::string debug_str = cs.debug_string();
EXPECT_NE(debug_str.find("selector_size=0"), std::string::npos);
EXPECT_NE(debug_str.find("output_nulls=0"), std::string::npos);
EXPECT_NE(debug_str.find("column size=1"), std::string::npos);
}
}
// ==================== ScalarFillWithSelector Tests ====================
TEST(ShortCircuitUtilTest, ScalarFillWithSelector_fill_true_false) {
auto true_col = ColumnHelper::create_column<DataTypeInt32>({10, 20});
auto false_col = ColumnHelper::create_column<DataTypeInt32>({30, 40, 50});
Selector true_selector = {0, 2};
Selector false_selector = {1, 3, 4};
auto result_type = std::make_shared<DataTypeInt32>();
auto result = ScalarFillWithSelector<TYPE_INT>::fill(result_type, true_col, true_selector,
false_col, false_selector, 5);
EXPECT_EQ(result->size(), 5);
EXPECT_EQ(result->get_int(0), 10); // from true_col[0]
EXPECT_EQ(result->get_int(1), 30); // from false_col[0]
EXPECT_EQ(result->get_int(2), 20); // from true_col[1]
EXPECT_EQ(result->get_int(3), 40); // from false_col[1]
EXPECT_EQ(result->get_int(4), 50); // from false_col[2]
}
TEST(ShortCircuitUtilTest, ScalarFillWithSelector_fill_nullable) {
auto true_col = ColumnHelper::create_nullable_column<DataTypeInt32>({10, 20}, {0, 1});
auto false_col = ColumnHelper::create_nullable_column<DataTypeInt32>({30}, {0});
Selector true_selector = {0, 2};
Selector false_selector = {1};
auto result_type = std::make_shared<DataTypeNullable>(std::make_shared<DataTypeInt32>());
auto result = ScalarFillWithSelector<TYPE_INT>::fill(result_type, true_col, true_selector,
false_col, false_selector, 3);
EXPECT_EQ(result->size(), 3);
EXPECT_FALSE(result->is_null_at(0)); // 10, not null
EXPECT_FALSE(result->is_null_at(1)); // 30, not null
EXPECT_TRUE(result->is_null_at(2)); // 20, null
}
TEST(ShortCircuitUtilTest, ScalarFillWithSelector_fill_with_columns_and_selectors) {
std::vector<ColumnAndSelector> columns_and_selectors;
// First column: positions 0, 2
ColumnAndSelector cs1;
cs1.column = ColumnHelper::create_column<DataTypeInt32>({100, 200});
cs1.selector = {0, 2};
columns_and_selectors.push_back(std::move(cs1));
// Second column: position 1
ColumnAndSelector cs2;
cs2.column = ColumnHelper::create_column<DataTypeInt32>({300});
cs2.selector = {1};
columns_and_selectors.push_back(std::move(cs2));
// Third: output null, position 3
ColumnAndSelector cs3;
cs3.column = nullptr;
cs3.selector = {3};
columns_and_selectors.push_back(std::move(cs3));
auto result_type = std::make_shared<DataTypeNullable>(std::make_shared<DataTypeInt32>());
auto result = ScalarFillWithSelector<TYPE_INT>::fill(result_type, columns_and_selectors, 4);
EXPECT_EQ(result->size(), 4);
const auto* nullable_result = assert_cast<const ColumnNullable*>(result.get());
const auto& nested_col = assert_cast<const ColumnInt32&>(nullable_result->get_nested_column());
EXPECT_EQ(nested_col.get_int(0), 100);
EXPECT_EQ(nested_col.get_int(1), 300);
EXPECT_EQ(nested_col.get_int(2), 200);
EXPECT_TRUE(result->is_null_at(3));
}
// ==================== NonScalarFillWithSelector Tests ====================
TEST(ShortCircuitUtilTest, NonScalarFillWithSelector_fill_true_false) {
auto true_col = ColumnHelper::create_column<DataTypeInt32>({10, 20});
auto false_col = ColumnHelper::create_column<DataTypeInt32>({30, 40, 50});
Selector true_selector = {0, 2};
Selector false_selector = {1, 3, 4};
auto result_type = std::make_shared<DataTypeInt32>();
auto result = NonScalarFillWithSelector::fill(result_type, true_col, true_selector, false_col,
false_selector, 5);
EXPECT_EQ(result->size(), 5);
EXPECT_EQ(result->get_int(0), 10);
EXPECT_EQ(result->get_int(1), 30);
EXPECT_EQ(result->get_int(2), 20);
EXPECT_EQ(result->get_int(3), 40);
EXPECT_EQ(result->get_int(4), 50);
}
TEST(ShortCircuitUtilTest, NonScalarFillWithSelector_fill_string) {
auto true_col = ColumnString::create();
true_col->insert_data("hello", 5);
true_col->insert_data("world", 5);
auto false_col = ColumnString::create();
false_col->insert_data("foo", 3);
Selector true_selector = {0, 2};
Selector false_selector = {1};
auto result_type = std::make_shared<DataTypeString>();
ColumnPtr true_col_ptr = std::move(true_col);
ColumnPtr false_col_ptr = std::move(false_col);
auto result = NonScalarFillWithSelector::fill(result_type, true_col_ptr, true_selector,
false_col_ptr, false_selector, 3);
EXPECT_EQ(result->size(), 3);
EXPECT_EQ(result->get_data_at(0).to_string(), "hello");
EXPECT_EQ(result->get_data_at(1).to_string(), "foo");
EXPECT_EQ(result->get_data_at(2).to_string(), "world");
}
TEST(ShortCircuitUtilTest, NonScalarFillWithSelector_fill_with_columns_and_selectors) {
std::vector<ColumnAndSelector> columns_and_selectors;
// First column
ColumnAndSelector cs1;
cs1.column = ColumnHelper::create_column<DataTypeInt32>({100, 200});
cs1.selector = {0, 2};
columns_and_selectors.push_back(std::move(cs1));
// Second column
ColumnAndSelector cs2;
cs2.column = ColumnHelper::create_column<DataTypeInt32>({300});
cs2.selector = {1};
columns_and_selectors.push_back(std::move(cs2));
// Third: output null
ColumnAndSelector cs3;
cs3.column = nullptr;
cs3.selector = {3};
columns_and_selectors.push_back(std::move(cs3));
auto result_type = std::make_shared<DataTypeNullable>(std::make_shared<DataTypeInt32>());
auto result = NonScalarFillWithSelector::fill(result_type, columns_and_selectors, 4);
EXPECT_EQ(result->size(), 4);
const auto* nullable_result = assert_cast<const ColumnNullable*>(result.get());
const auto& nested_col = assert_cast<const ColumnInt32&>(nullable_result->get_nested_column());
EXPECT_EQ(nested_col.get_int(0), 100);
EXPECT_EQ(nested_col.get_int(1), 300);
EXPECT_EQ(nested_col.get_int(2), 200);
EXPECT_TRUE(result->is_null_at(3));
}
TEST(ShortCircuitUtilTest, NonScalarFillWithSelector_fill_string_with_null) {
std::vector<ColumnAndSelector> columns_and_selectors;
// First column: string
auto str_col = ColumnString::create();
str_col->insert_data("hello", 5);
str_col->insert_data("world", 5);
ColumnAndSelector cs1;
cs1.column = std::move(str_col);
cs1.selector = {0, 2};
columns_and_selectors.push_back(std::move(cs1));
// Second: null
ColumnAndSelector cs2;
cs2.column = nullptr;
cs2.selector = {1};
columns_and_selectors.push_back(std::move(cs2));
auto result_type = std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>());
auto result = NonScalarFillWithSelector::fill(result_type, columns_and_selectors, 3);
EXPECT_EQ(result->size(), 3);
EXPECT_FALSE(result->is_null_at(0));
EXPECT_TRUE(result->is_null_at(1));
EXPECT_FALSE(result->is_null_at(2));
EXPECT_EQ(result->get_data_at(0).to_string(), "hello");
EXPECT_EQ(result->get_data_at(2).to_string(), "world");
}
// ==================== Edge Cases ====================
TEST(ShortCircuitUtilTest, ScalarFillWithSelector_all_true) {
auto true_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
auto false_col = ColumnHelper::create_column<DataTypeInt32>({});
Selector true_selector = {0, 1, 2};
Selector false_selector = {};
auto result_type = std::make_shared<DataTypeInt32>();
auto result = ScalarFillWithSelector<TYPE_INT>::fill(result_type, true_col, true_selector,
false_col, false_selector, 3);
EXPECT_EQ(result->size(), 3);
EXPECT_EQ(result->get_int(0), 1);
EXPECT_EQ(result->get_int(1), 2);
EXPECT_EQ(result->get_int(2), 3);
}
TEST(ShortCircuitUtilTest, ScalarFillWithSelector_all_false) {
auto true_col = ColumnHelper::create_column<DataTypeInt32>({});
auto false_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
Selector true_selector = {};
Selector false_selector = {0, 1, 2};
auto result_type = std::make_shared<DataTypeInt32>();
auto result = ScalarFillWithSelector<TYPE_INT>::fill(result_type, true_col, true_selector,
false_col, false_selector, 3);
EXPECT_EQ(result->size(), 3);
EXPECT_EQ(result->get_int(0), 1);
EXPECT_EQ(result->get_int(1), 2);
EXPECT_EQ(result->get_int(2), 3);
}
TEST(ShortCircuitUtilTest, ScalarFillWithSelector_all_null) {
std::vector<ColumnAndSelector> columns_and_selectors;
ColumnAndSelector cs;
cs.column = nullptr;
cs.selector = {0, 1, 2};
columns_and_selectors.push_back(std::move(cs));
auto result_type = std::make_shared<DataTypeNullable>(std::make_shared<DataTypeInt32>());
auto result = ScalarFillWithSelector<TYPE_INT>::fill(result_type, columns_and_selectors, 3);
EXPECT_EQ(result->size(), 3);
EXPECT_TRUE(result->is_null_at(0));
EXPECT_TRUE(result->is_null_at(1));
EXPECT_TRUE(result->is_null_at(2));
}
// ==================== ConditionColumnView Tests ====================
TEST(ShortCircuitUtilTest, ConditionColumnView_non_nullable_no_selector) {
// Create a boolean column: [true, false, true, false]
auto col = ColumnHelper::create_column<DataTypeUInt8>({1, 0, 1, 0});
auto view = ConditionColumnView::create(col, nullptr, 4);
Selector null_selector;
Selector true_selector;
Selector false_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto true_func = [&](size_t self_index, size_t executor_index) {
true_selector.push_back(executor_index);
};
auto false_func = [&](size_t self_index, size_t executor_index) {
false_selector.push_back(executor_index);
};
view.for_each(null_func, true_func, false_func);
EXPECT_EQ(null_selector.size(), 0);
EXPECT_EQ(true_selector.size(), 2);
EXPECT_EQ(false_selector.size(), 2);
EXPECT_EQ(true_selector[0], 0);
EXPECT_EQ(true_selector[1], 2);
EXPECT_EQ(false_selector[0], 1);
EXPECT_EQ(false_selector[1], 3);
}
TEST(ShortCircuitUtilTest, ConditionColumnView_nullable_no_selector) {
// Create a nullable boolean column: [true, NULL, false, NULL]
auto col = ColumnHelper::create_nullable_column<DataTypeUInt8>({1, 0, 0, 0}, {0, 1, 0, 1});
auto view = ConditionColumnView::create(col, nullptr, 4);
Selector null_selector;
Selector true_selector;
Selector false_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto true_func = [&](size_t self_index, size_t executor_index) {
true_selector.push_back(executor_index);
};
auto false_func = [&](size_t self_index, size_t executor_index) {
false_selector.push_back(executor_index);
};
view.for_each(null_func, true_func, false_func);
EXPECT_EQ(null_selector.size(), 2);
EXPECT_EQ(true_selector.size(), 1);
EXPECT_EQ(false_selector.size(), 1);
EXPECT_EQ(null_selector[0], 1);
EXPECT_EQ(null_selector[1], 3);
EXPECT_EQ(true_selector[0], 0);
EXPECT_EQ(false_selector[0], 2);
}
TEST(ShortCircuitUtilTest, ConditionColumnView_with_selector) {
// Create a boolean column: [true, false, true, false, true]
auto col = ColumnHelper::create_column<DataTypeUInt8>({1, 0, 1, 0, 1});
// Only select positions 1, 3 (result indices should be 10, 20)
Selector input_selector = {10, 20};
auto view = ConditionColumnView::create(col, &input_selector, 2);
Selector null_selector;
Selector true_selector;
Selector false_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto true_func = [&](size_t self_index, size_t executor_index) {
true_selector.push_back(executor_index);
};
auto false_func = [&](size_t self_index, size_t executor_index) {
false_selector.push_back(executor_index);
};
view.for_each(null_func, true_func, false_func);
EXPECT_EQ(null_selector.size(), 0);
// col[0]=true -> result_index=10, col[1]=false -> result_index=20
EXPECT_EQ(true_selector.size(), 1);
EXPECT_EQ(false_selector.size(), 1);
EXPECT_EQ(true_selector[0], 10);
EXPECT_EQ(false_selector[0], 20);
}
TEST(ShortCircuitUtilTest, ConditionColumnView_const_true) {
// Create a const boolean column: const(true, 5)
auto col = ColumnHelper::create_column<DataTypeUInt8>({1});
ColumnPtr const_col = ColumnConst::create(col, 5);
auto view = ConditionColumnView::create(const_col, nullptr, 5);
Selector null_selector;
Selector true_selector;
Selector false_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto true_func = [&](size_t self_index, size_t executor_index) {
true_selector.push_back(executor_index);
};
auto false_func = [&](size_t self_index, size_t executor_index) {
false_selector.push_back(executor_index);
};
view.for_each(null_func, true_func, false_func);
EXPECT_EQ(null_selector.size(), 0);
EXPECT_EQ(true_selector.size(), 5);
EXPECT_EQ(false_selector.size(), 0);
for (size_t i = 0; i < 5; ++i) {
EXPECT_EQ(true_selector[i], i);
}
}
TEST(ShortCircuitUtilTest, ConditionColumnView_const_false) {
// Create a const boolean column: const(false, 3)
auto col = ColumnHelper::create_column<DataTypeUInt8>({0});
ColumnPtr const_col = ColumnConst::create(col, 3);
auto view = ConditionColumnView::create(const_col, nullptr, 3);
Selector null_selector;
Selector true_selector;
Selector false_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto true_func = [&](size_t self_index, size_t executor_index) {
true_selector.push_back(executor_index);
};
auto false_func = [&](size_t self_index, size_t executor_index) {
false_selector.push_back(executor_index);
};
view.for_each(null_func, true_func, false_func);
EXPECT_EQ(null_selector.size(), 0);
EXPECT_EQ(true_selector.size(), 0);
EXPECT_EQ(false_selector.size(), 3);
}
TEST(ShortCircuitUtilTest, ConditionColumnView_const_null) {
// Create a const nullable boolean column: const(NULL, 3)
auto col = ColumnHelper::create_nullable_column<DataTypeUInt8>({0}, {1});
ColumnPtr const_col = ColumnConst::create(col, 3);
auto view = ConditionColumnView::create(const_col, nullptr, 3);
Selector null_selector;
Selector true_selector;
Selector false_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto true_func = [&](size_t self_index, size_t executor_index) {
true_selector.push_back(executor_index);
};
auto false_func = [&](size_t self_index, size_t executor_index) {
false_selector.push_back(executor_index);
};
view.for_each(null_func, true_func, false_func);
EXPECT_EQ(null_selector.size(), 3);
EXPECT_EQ(true_selector.size(), 0);
EXPECT_EQ(false_selector.size(), 0);
}
// ==================== ConditionColumnNullView Tests ====================
TEST(ShortCircuitUtilTest, ConditionColumnNullView_non_nullable_no_selector) {
// Non-nullable column: all values are not null
auto col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3, 4});
auto view = ConditionColumnNullView::create(col, nullptr, 4);
Selector null_selector;
Selector not_null_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto not_null_func = [&](size_t self_index, size_t executor_index) {
not_null_selector.push_back(executor_index);
};
view.for_each(null_func, not_null_func);
EXPECT_EQ(null_selector.size(), 0);
EXPECT_EQ(not_null_selector.size(), 4);
for (size_t i = 0; i < 4; ++i) {
EXPECT_EQ(not_null_selector[i], i);
}
}
TEST(ShortCircuitUtilTest, ConditionColumnNullView_nullable_no_selector) {
// Nullable column: [1, NULL, 3, NULL, 5]
auto col =
ColumnHelper::create_nullable_column<DataTypeInt32>({1, 0, 3, 0, 5}, {0, 1, 0, 1, 0});
auto view = ConditionColumnNullView::create(col, nullptr, 5);
Selector null_selector;
Selector not_null_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto not_null_func = [&](size_t self_index, size_t executor_index) {
not_null_selector.push_back(executor_index);
};
view.for_each(null_func, not_null_func);
EXPECT_EQ(null_selector.size(), 2);
EXPECT_EQ(not_null_selector.size(), 3);
EXPECT_EQ(null_selector[0], 1);
EXPECT_EQ(null_selector[1], 3);
EXPECT_EQ(not_null_selector[0], 0);
EXPECT_EQ(not_null_selector[1], 2);
EXPECT_EQ(not_null_selector[2], 4);
}
TEST(ShortCircuitUtilTest, ConditionColumnNullView_with_selector) {
// Nullable column: [1, NULL, 3, NULL, 5]
auto col =
ColumnHelper::create_nullable_column<DataTypeInt32>({1, 0, 3, 0, 5}, {0, 1, 0, 1, 0});
// Only process first 3 elements, with custom result indices
Selector input_selector = {100, 200, 300};
auto view = ConditionColumnNullView::create(col, &input_selector, 3);
Selector null_selector;
Selector not_null_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto not_null_func = [&](size_t self_index, size_t executor_index) {
not_null_selector.push_back(executor_index);
};
view.for_each(null_func, not_null_func);
// col[0]=1 not null -> executor_index=100
// col[1]=NULL -> executor_index=200
// col[2]=3 not null -> executor_index=300
EXPECT_EQ(null_selector.size(), 1);
EXPECT_EQ(not_null_selector.size(), 2);
EXPECT_EQ(null_selector[0], 200);
EXPECT_EQ(not_null_selector[0], 100);
EXPECT_EQ(not_null_selector[1], 300);
}
TEST(ShortCircuitUtilTest, ConditionColumnNullView_const_not_null) {
// Const column: const(42, 4)
auto col = ColumnHelper::create_column<DataTypeInt32>({42});
ColumnPtr const_col = ColumnConst::create(col, 4);
auto view = ConditionColumnNullView::create(const_col, nullptr, 4);
Selector null_selector;
Selector not_null_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto not_null_func = [&](size_t self_index, size_t executor_index) {
not_null_selector.push_back(executor_index);
};
view.for_each(null_func, not_null_func);
EXPECT_EQ(null_selector.size(), 0);
EXPECT_EQ(not_null_selector.size(), 4);
}
TEST(ShortCircuitUtilTest, ConditionColumnNullView_const_null) {
// Const nullable column: const(NULL, 3)
auto col = ColumnHelper::create_nullable_column<DataTypeInt32>({0}, {1});
ColumnPtr const_col = ColumnConst::create(col, 3);
auto view = ConditionColumnNullView::create(const_col, nullptr, 3);
Selector null_selector;
Selector not_null_selector;
auto null_func = [&](size_t self_index, size_t executor_index) {
null_selector.push_back(executor_index);
};
auto not_null_func = [&](size_t self_index, size_t executor_index) {
not_null_selector.push_back(executor_index);
};
view.for_each(null_func, not_null_func);
EXPECT_EQ(null_selector.size(), 3);
EXPECT_EQ(not_null_selector.size(), 0);
}
// ==================== Additional Edge Cases ====================
TEST(ShortCircuitUtilTest, MutableColumnNullView_insert_from_const) {
// Source: const(100, 3)
auto src_col_inner = ColumnHelper::create_column<DataTypeInt32>({100});
ColumnPtr src_col = ColumnConst::create(src_col_inner, 3);
auto src_view = ColumnNullConstView::create(src_col);
MutableColumnPtr dst_col = ColumnInt32::create();
auto dst_view = MutableColumnNullView::create(dst_col);
// Insert from positions 0, 1, 2 (all should be 100 since it's const)
dst_view.insert_from(src_view, 0);
dst_view.insert_from(src_view, 1);
dst_view.insert_from(src_view, 2);
EXPECT_EQ(dst_col->size(), 3);
EXPECT_EQ(dst_col->get_int(0), 100);
EXPECT_EQ(dst_col->get_int(1), 100);
EXPECT_EQ(dst_col->get_int(2), 100);
}
TEST(ShortCircuitUtilTest, MutableColumnNullView_insert_from_non_nullable_to_nullable) {
// Source: non-nullable [1, 2, 3]
auto src_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
auto src_view = ColumnNullConstView::create(src_col);
// Dest: nullable column
auto nested_col = ColumnInt32::create();
auto null_map = ColumnUInt8::create();
MutableColumnPtr dst_col = ColumnNullable::create(std::move(nested_col), std::move(null_map));
auto dst_view = MutableColumnNullView::create(dst_col);
dst_view.insert_from(src_view, 0);
dst_view.insert_from(src_view, 1);
dst_view.insert_from(src_view, 2);
EXPECT_EQ(dst_col->size(), 3);
// All values should be non-null since source is non-nullable
EXPECT_FALSE(dst_col->is_null_at(0));
EXPECT_FALSE(dst_col->is_null_at(1));
EXPECT_FALSE(dst_col->is_null_at(2));
}
TEST(ShortCircuitUtilTest, NonScalarFillWithSelector_empty_columns_and_selectors) {
std::vector<ColumnAndSelector> columns_and_selectors;
// All empty
ColumnAndSelector cs;
cs.column = ColumnHelper::create_column<DataTypeInt32>({});
cs.selector = {};
columns_and_selectors.push_back(std::move(cs));
auto result_type = std::make_shared<DataTypeInt32>();
auto result = NonScalarFillWithSelector::fill(result_type, columns_and_selectors, 0);
EXPECT_EQ(result->size(), 0);
}
TEST(ShortCircuitUtilTest, NonScalarFillWithSelector_all_null) {
std::vector<ColumnAndSelector> columns_and_selectors;
ColumnAndSelector cs;
cs.column = nullptr;
cs.selector = {0, 1, 2};
columns_and_selectors.push_back(std::move(cs));
auto result_type = std::make_shared<DataTypeNullable>(std::make_shared<DataTypeInt32>());
auto result = NonScalarFillWithSelector::fill(result_type, columns_and_selectors, 3);
EXPECT_EQ(result->size(), 3);
EXPECT_TRUE(result->is_null_at(0));
EXPECT_TRUE(result->is_null_at(1));
EXPECT_TRUE(result->is_null_at(2));
}
TEST(ShortCircuitUtilTest, ColumnNullConstViewScalar_const_column) {
auto col = ColumnHelper::create_column<DataTypeInt32>({42});
ColumnPtr const_col = ColumnConst::create(col, 5);
auto view = ColumnNullConstViewScalar<TYPE_INT>::create(const_col);
EXPECT_EQ(view.data.size(), 1);
EXPECT_EQ(view.data[0], 42);
EXPECT_EQ(view.null_map, nullptr);
EXPECT_TRUE(view.is_const);
}
TEST(ShortCircuitUtilTest, ColumnNullConstViewScalar_const_nullable_column) {
auto col = ColumnHelper::create_nullable_column<DataTypeInt32>({42}, {0});
ColumnPtr const_col = ColumnConst::create(col, 5);
auto view = ColumnNullConstViewScalar<TYPE_INT>::create(const_col);
EXPECT_EQ(view.data.size(), 1);
EXPECT_EQ(view.data[0], 42);
EXPECT_NE(view.null_map, nullptr);
EXPECT_EQ((*view.null_map)[0], 0);
EXPECT_TRUE(view.is_const);
}
} // namespace doris