diff --git a/src/Storages/StorageMerge.cpp b/src/Storages/StorageMerge.cpp index e096811e5b91..79efab9e9d7c 100644 --- a/src/Storages/StorageMerge.cpp +++ b/src/Storages/StorageMerge.cpp @@ -145,8 +145,43 @@ bool StorageMerge::canMoveConditionsToPrewhere() const /// If new table that matches regexp for current storage and doesn't support PREWHERE /// will appear after this check and before calling "read" method, the optimized query may fail. /// Since it's quite rare case, we just ignore this possibility. + const auto & table_doesnt_support_prewhere = getFirstTable([](const auto & table) { return !table->canMoveConditionsToPrewhere(); }); + bool can_move = (table_doesnt_support_prewhere == nullptr); - return getFirstTable([](const auto & table) { return !table->canMoveConditionsToPrewhere(); }) == nullptr; + if (!can_move) + return false; + + if (!getInMemoryMetadataPtr()) + return false; + + std::unordered_map column_types; + for (const auto & name_type : getInMemoryMetadataPtr()->getColumns().getAll()) + { + column_types.emplace(name_type.name, name_type.type.get()); + } + + /// Check that all tables have the same column types, otherwise prewhere will fail + forEachTable([&](const StoragePtr & table) + { + const auto & metadata_ptr = table->getInMemoryMetadataPtr(); + if (!metadata_ptr) + can_move = false; + + if (!can_move) + return; + + for (const auto & column : metadata_ptr->getColumns().getAll()) + { + const auto * src_type = column_types[column.name]; + if (src_type && !src_type->equals(*column.type)) + { + can_move = false; + return; + } + } + }); + + return can_move; } bool StorageMerge::mayBenefitFromIndexForIn(const ASTPtr & left_in_operand, ContextPtr query_context, const StorageMetadataPtr & /*metadata_snapshot*/) const diff --git a/tests/queries/0_stateless/02518_merge_engine_nullable_43324.reference b/tests/queries/0_stateless/02518_merge_engine_nullable_43324.reference new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/queries/0_stateless/02518_merge_engine_nullable_43324.sql b/tests/queries/0_stateless/02518_merge_engine_nullable_43324.sql new file mode 100644 index 000000000000..1223c4e95eac --- /dev/null +++ b/tests/queries/0_stateless/02518_merge_engine_nullable_43324.sql @@ -0,0 +1,18 @@ + +DROP TABLE IF EXISTS foo; +DROP TABLE IF EXISTS foo__fuzz_0; +DROP TABLE IF EXISTS foo_merge; + +CREATE TABLE foo (`Id` Int32, `Val` Int32) ENGINE = MergeTree ORDER BY Id; +CREATE TABLE foo__fuzz_0 (`Id` Int64, `Val` Nullable(Int32)) ENGINE = MergeTree ORDER BY Id; + +INSERT INTO foo SELECT number, number % 5 FROM numbers(10); +INSERT INTO foo__fuzz_0 SELECT number, number % 5 FROM numbers(10); + +CREATE TABLE merge1 AS foo ENGINE = Merge(currentDatabase(), '^foo'); +CREATE TABLE merge2 (`Id` Int32, `Val` Int32) ENGINE = Merge(currentDatabase(), '^foo'); +CREATE TABLE merge3 (`Id` Int32, `Val` Int32) ENGINE = Merge(currentDatabase(), '^foo__fuzz_0'); + +SELECT * FROM merge1 WHERE Val = 3 AND Val = 1; +SELECT * FROM merge2 WHERE Val = 3 AND Val = 1; +SELECT * FROM merge3 WHERE Val = 3 AND Val = 1;