#27685
{
    DataTypePtr left_type_strict = removeNullable(recursiveRemoveLowCardinality(left_type));
    DataTypePtr right_type_strict = removeNullable(recursiveRemoveLowCardinality(right_type));
    return left_type_strict->equals(*right_type_strict);
}
ColumnPtr getColumnAsMask(const Block & block, const String & column_name)
{
    if (column_name.empty())
        return nullptr;
    const auto & src_col = block.getByName(column_name);
    DataTypePtr col_type = recursiveRemoveLowCardinality(src_col.type);
    if (isNothing(col_type))
        return ColumnUInt8::create(block.rows(), 0);
    const auto & join_condition_col = recursiveRemoveLowCardinality(src_col.column->convertToFullColumnIfConst());
    if (const auto * nullable_col = typeid_cast<const ColumnNullable *>(join_condition_col.get()))
    {
        if (isNothing(assert_cast<const DataTypeNullable &>(*col_type).getNestedType()))
            return ColumnUInt8::create(block.rows(), 0);
        
        const auto & nest_col = assert_cast<const ColumnUInt8 &>(nullable_col->getNestedColumn());
        const auto & null_map = nullable_col->getNullMapColumn();
        auto res = ColumnUInt8::create(nullable_col->size(), 0);
        for (size_t i = 0, sz = nullable_col->size(); i < sz; ++i)
            res->getData()[i] = !null_map.getData()[i] && nest_col.getData()[i];
        return res;
    }
    else
        return join_condition_col;
}
void splitAdditionalColumns(const Names & key_names, const Block & sample_block, Block & block_keys, Block & block_others)