diff --git a/be/test/exec/hash_map/hash_table_method_test.cpp b/be/test/exec/hash_map/hash_table_method_test.cpp new file mode 100644 index 00000000000000..31a1842112335f --- /dev/null +++ b/be/test/exec/hash_map/hash_table_method_test.cpp @@ -0,0 +1,131 @@ +// 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 + +#include "testutil/column_helper.h" +#include "vec/common/columns_hashing.h" +#include "vec/common/hash_table/hash.h" +#include "vec/common/hash_table/hash_map_context.h" +#include "vec/common/hash_table/ph_hash_map.h" +#include "vec/data_types/data_type_number.h" + +namespace doris::vectorized { + +template +void test_insert(HashMethodType& method, ColumnPtrs column) { + using State = typename HashMethodType::State; + ColumnRawPtrs key_raw_columns; + for (auto column : column) { + key_raw_columns.push_back(column.get()); + } + State state(key_raw_columns); + const size_t rows = key_raw_columns[0]->size(); + method.init_serialized_keys(key_raw_columns, rows); + + for (int i = 0; i < rows; i++) { + auto creator = [&](const auto& ctor, auto& key, auto& origin) { ctor(key, i); }; + + auto creator_for_null_key = [&](auto& mapped) { + throw doris::Exception(ErrorCode::INTERNAL_ERROR, + "no null key"); // NOLINT + }; + method.lazy_emplace(state, i, creator, creator_for_null_key); + } +} + +template +void test_find(HashMethodType& method, ColumnPtrs column, + const std::vector& except_result) { + using State = typename HashMethodType::State; + ColumnRawPtrs key_raw_columns; + for (auto column : column) { + key_raw_columns.push_back(column.get()); + } + State state(key_raw_columns); + const size_t rows = key_raw_columns[0]->size(); + method.init_serialized_keys(key_raw_columns, rows); + for (size_t i = 0; i < rows; ++i) { + auto find_result = method.find(state, i); + if (find_result.is_found()) { + EXPECT_EQ(except_result[i], find_result.get_mapped()); + } else { + EXPECT_EQ(except_result[i], -1); // not found + } + } +} + +TEST(HashTableMethodTest, testMethodOneNumber) { + MethodOneNumber>> method; + + test_insert(method, {ColumnHelper::create_column({1, 2, 3, 4, 5})}); + + test_find(method, {ColumnHelper::create_column({1, 2, 3, 4, 5})}, + {0, 1, 2, 3, 4}); + + test_find(method, {ColumnHelper::create_column({1, 2, 7, 4, 6, 5})}, + {0, 1, -1, 3, -1, 4}); +} + +TEST(HashTableMethodTest, testMethodFixed) { + MethodKeysFixed>> method( + Sizes {sizeof(int), sizeof(int)}); + + test_insert(method, {ColumnHelper::create_column({1, 2, 3, 4, 5}), + ColumnHelper::create_column({1, 2, 3, 4, 5})}); + + test_find(method, + {ColumnHelper::create_column({1, 2, 3, 4, 5}), + ColumnHelper::create_column({1, 2, 3, 4, 5})}, + {0, 1, 2, 3, 4}); + + test_find(method, + {ColumnHelper::create_column({1, 2, 7, 4, 6, 5}), + ColumnHelper::create_column({1, 2, 7, 4, 6, 5})}, + {0, 1, -1, 3, -1, 4}); +} + +TEST(HashTableMethodTest, testMethodSerialized) { + MethodSerialized> method; + + test_insert(method, {ColumnHelper::create_column({1, 2, 3, 4, 5}), + ColumnHelper::create_column({"1", "2", "3", "4", "5"})}); + + test_find(method, + {ColumnHelper::create_column({1, 2, 3, 4, 5}), + ColumnHelper::create_column({"1", "2", "3", "4", "5"})}, + {0, 1, 2, 3, 4}); + + test_find(method, + {ColumnHelper::create_column({1, 2, 7, 4, 6, 5}), + ColumnHelper::create_column({"1", "2", "7", "4", "6", "5"})}, + {0, 1, -1, 3, -1, 4}); +} + +TEST(HashTableMethodTest, testMethodStringNoCache) { + MethodStringNoCache> method; + + test_insert(method, {ColumnHelper::create_column({"1", "2", "3", "4", "5"})}); + + test_find(method, {ColumnHelper::create_column({"1", "2", "3", "4", "5"})}, + {0, 1, 2, 3, 4}); + + test_find(method, {ColumnHelper::create_column({"1", "2", "7", "4", "6", "5"})}, + {0, 1, -1, 3, -1, 4}); +} + +} // namespace doris::vectorized \ No newline at end of file diff --git a/be/test/testutil/column_helper.cpp b/be/test/testutil/column_helper.cpp new file mode 100644 index 00000000000000..b00a681ec72cdf --- /dev/null +++ b/be/test/testutil/column_helper.cpp @@ -0,0 +1,39 @@ +// 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 "column_helper.h" + +#include + +#include "vec/data_types/data_type_number.h" + +namespace doris::vectorized { + +TEST(ColumnHelperTest, test) { + EXPECT_TRUE(ColumnHelper::column_equal( + ColumnHelper::create_column({1, 2, 3, 4, 5}), + ColumnHelper::create_column({1, 2, 3, 4, 5}))); + + EXPECT_FALSE(ColumnHelper::column_equal( + ColumnHelper::create_column({1, 2, 3, 4, 5}), + ColumnHelper::create_column({1, 2, 3, 4, 5, 6}))); + + EXPECT_FALSE(ColumnHelper::column_equal( + ColumnHelper::create_column({1, 1, 3, 4, 5}), + ColumnHelper::create_column({1, 2, 3, 4, 5}))); +} + +} // namespace doris::vectorized diff --git a/be/test/testutil/column_helper.h b/be/test/testutil/column_helper.h new file mode 100644 index 00000000000000..cf3b4fcaf61700 --- /dev/null +++ b/be/test/testutil/column_helper.h @@ -0,0 +1,55 @@ +// 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 +#include + +#include "vec/data_types/data_type_string.h" + +namespace doris::vectorized { +struct ColumnHelper { +public: + template + static ColumnPtr create_column(const std::vector& datas) { + auto column = DataType::ColumnType::create(); + if constexpr (std::is_same_v) { + for (const auto& data : datas) { + column->insert_data(data.data(), data.size()); + } + } else { + for (const auto& data : datas) { + column->insert_value(data); + } + } + return std::move(column); + } + + static bool column_equal(const ColumnPtr& column1, const ColumnPtr& column2) { + if (column1->size() != column2->size()) { + return false; + } + for (size_t i = 0; i < column1->size(); i++) { + if (column1->compare_at(i, i, *column2, 1) != 0) { + return false; + } + } + return true; + } +}; +} // namespace doris::vectorized