```sql
DROP TABLE IF EXISTS tp;

create table tp (d1 Int32, d2 Int32, eventcnt Int64,
projection p (select sum(eventcnt), d1 group by d1)) 
engine = SummingMergeTree order by (d1, d2);

set allow_experimental_projection_optimization = 1, force_optimize_projection = 1;

select sum(eventcnt) eventcnt, d1
from tp
group by d1;

DB::Exception: No projection is used when allow_experimental_projection_optimization = 1.

```

The exception message is also incorrect, should be "when force_optimize_projection = 1".

});
                pool.wait();
            }
            
            size_t next_part = 0;
            for (size_t part_index = 0; part_index < parts.size(); ++part_index)
            {
                auto & part = parts_with_ranges[part_index];
                if (!part.data_part)
                    continue;
                sum_ranges += part.ranges.size();
                sum_marks += part.getMarksCount();
                if (next_part != part_index)
                    std::swap(parts_with_ranges[next_part], part);
                ++next_part;
            }
            parts_with_ranges.resize(next_part);
        }
        if (metadata_snapshot->hasPrimaryKey())
        {
            auto description = key_condition->getDescription();
            index_stats->emplace_back(ReadFromMergeTree::IndexStat{
                .type = ReadFromMergeTree::IndexType::PrimaryKey,
                .condition = std::move(description.condition),
                .used_keys = std::move(description.used_keys),
                .num_parts_after = sum_parts_pk.load(std::memory_order_relaxed),
                .num_granules_after = sum_marks_pk.load(std::memory_order_relaxed)});
        }
        for (const auto & index_and_condition : useful_indices)
        {