```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".

virt_columns,
            step_settings,
            num_streams_for_lonely_parts,
            ReadFromMergeTree::ReadType::Default);
        plan->addStep(std::move(step));
        
        if (!out_projection)
            out_projection = createProjection(plan->getCurrentDataStream().header);
        auto expression_step = std::make_unique<ExpressionStep>(
            plan->getCurrentDataStream(),
            metadata_snapshot->getSortingKey().expression->getActionsDAG().clone());
        expression_step->setStepDescription("Calculate sorting key expression");
        plan->addStep(std::move(expression_step));
        partition_plans.emplace_back(std::move(plan));
    }
    if (partition_plans.empty())
        return {};
    if (partition_plans.size() == 1)
        return std::move(partition_plans.front());
    auto result_header = partition_plans.front()->getCurrentDataStream().header;
    DataStreams input_streams;
    for (const auto & partition_plan : partition_plans)
        input_streams.push_back(partition_plan->getCurrentDataStream());
    auto union_step = std::make_unique<UnionStep>(std::move(input_streams), result_header);
    union_step->setStepDescription("Unite sources after FINAL");
    QueryPlanPtr plan = std::make_unique<QueryPlan>();
    plan->unitePlans(std::move(union_step), std::move(partition_plans));
    return plan;
}
MarkRanges MergeTreeDataSelectExecutor::markRangesFromPKRange(