https://s3.amazonaws.com/clickhouse-test-reports/42778/66c179217cdfdee1ba0d4b4b577b1a62655caed0/fuzzer_astfuzzermsan//report.html

Minimal example
```sql
#!/usr/bin/clickhouse-client --queries-file

DROP TABLE IF EXISTS tab1;
DROP TABLE IF EXISTS tab2;

SET allow_suspicious_low_cardinality_types = 1;

create table tab1 (a1 Int32, b1 Int32) engine = MergeTree order by a1;
create table tab2 (a2 LowCardinality(Int32), b2 Int32) engine = MergeTree order by a2;

insert into tab1 values (1, 2);
insert into tab2 values (1, 2);

SET join_use_nulls = 1;

SELECT 1 FROM tab1 FULL OUTER JOIN tab2 ON b1 - 2 = a2 OR a1 = b2;

```
Block & block,
    const Block & block_with_columns_to_add,
    const std::vector<const Maps *> & maps_,
    bool is_join_get) const
{
    constexpr JoinFeatures<KIND, STRICTNESS> jf;
    std::vector<JoinOnKeyColumns> join_on_keys;
    const auto & onexprs = table_join->getClauses();
    for (size_t i = 0; i < onexprs.size(); ++i)
    {
        const auto & key_names = !is_join_get ? onexprs[i].key_names_left : onexprs[i].key_names_right;
        join_on_keys.emplace_back(block, key_names, onexprs[i].condColumnNames().first, key_sizes[i]);
    }
    size_t existing_columns = block.columns();
    /** If you use FULL or RIGHT JOIN, then the columns from the "left" table must be materialized.
      * Because if they are constants, then in the "not joined" rows, they may have different values
      *  - default values, which can differ from the values of these constants.
      */
    if constexpr (jf.right || jf.full)
    {
        materializeBlockInplace(block);