Repository: ClickHouse/ClickHouse
File: src/Interpreters/InterpreterInsertQuery.cpp (C++)

Code before:

void InterpreterInsertQuery::extendQueryLogElemImpl(QueryLogElement & elem, const ASTPtr &, ContextPtr context_) const
{
    extendQueryLogElemImpl(elem, context_);
}

void InterpreterInsertQuery::setInsertContextValues(StoragePtr table)
{
    auto const & insert_query = query_ptr->as<ASTInsertQuery &>();

    std::optional<Names> insert_columns;
    if (insert_query.columns)
    {
        const auto columns_ast = processColumnTransformers(getContext()->getCurrentDatabase(), table, table->getInMemoryMetadataPtr(), insert_query.columns);
        Names names;
        names.reserve(columns_ast->children.size());
        for (const auto & identifier : columns_ast->children)
        {
            std::string current_name = identifier->getColumnName();
            names.emplace_back(std::move(current_name));
        }

        insert_columns = std::move(names);
    }

    getContext()->setInsertionTable(insert_query.table_id, insert_columns, table->getInMemoryMetadataPtr()->columns);
}

void registerInterpreterInsertQuery(InterpreterFactory & factory)
{
    auto create_fn = [] (const InterpreterFactory::Arguments & args)
    {
        return std::make_unique<InterpreterInsertQuery>(
            args.query,
            args.context,
            args.allow_materialized,
            /* no_squash */false,
            /* no_destination */false,
            /* async_insert */false);
    };
    factory.registerInterpreter("InterpreterInsertQuery", create_fn);
}


}


Review comment (suggestion):
This introduces a heap allocation and a full `ColumnsDescription` copy when preparing the insert context. If callers only need read-only access, using `std::shared_ptr<const ColumnsDescription>` and sharing an existing immutable instance (when available) would avoid both mutation risk and potentially reduce per-insert overhead.
```suggestion
    getContext()->setInsertionTable(insert_query.table_id, insert_columns, table->getInMemoryMetadataPtr()->getColumnsPtr());
```

Code after:

void InterpreterInsertQuery::extendQueryLogElemImpl(QueryLogElement & elem, const ASTPtr &, ContextPtr context_) const
{
    extendQueryLogElemImpl(elem, context_);
}

void InterpreterInsertQuery::setInsertContextValues(StoragePtr table)
{
    auto const & insert_query = query_ptr->as<ASTInsertQuery &>();

    std::optional<Names> insert_columns;
    if (insert_query.columns)
    {
        const auto columns_ast = processColumnTransformers(getContext()->getCurrentDatabase(), table, table->getInMemoryMetadataPtr(), insert_query.columns);
        Names names;
        names.reserve(columns_ast->children.size());
        for (const auto & identifier : columns_ast->children)
        {
            std::string current_name = identifier->getColumnName();
            names.emplace_back(std::move(current_name));
        }

        insert_columns = std::move(names);
    }

    getContext()->setInsertionTable(insert_query.table_id, insert_columns, std::make_shared<ColumnsDescription>(table->getInMemoryMetadataPtr()->columns));
}

void registerInterpreterInsertQuery(InterpreterFactory & factory)
{
    auto create_fn = [] (const InterpreterFactory::Arguments & args)
    {
        return std::make_unique<InterpreterInsertQuery>(
            args.query,
            args.context,
            args.allow_materialized,
            /* no_squash */false,
            /* no_destination */false,
            /* async_insert */false);
    };
    factory.registerInterpreter("InterpreterInsertQuery", create_fn);
}


}