Repository: ClickHouse/ClickHouse
File: src/Storages/VirtualColumnUtils.cpp (C++)

Code before:
        if (storage_columns.has(name))
            return;

        const auto & type = pair.getTypeInStorage();
        desc.addEphemeral(name, type, "");
    };

    for (const auto & item : getCommonVirtualsForFileLikeStorage())
        add_virtual(item);

    if (!path.empty() && context->getSettingsRef()[Setting::use_hive_partitioning])
    {
        const auto format_settings = format_settings_ ? *format_settings_ : getFormatSettings(context);
        const auto map = HivePartitioningUtils::parseHivePartitioningKeysAndValues(path);
        for (const auto & item : map)
        {
            auto type = tryInferDataTypeByEscapingRule(std::string(item.second), format_settings, FormatSettings::EscapingRule::Raw, nullptr);
            if (type == nullptr)
                type = std::make_shared<DataTypeString>();
            if (type->canBeInsideLowCardinality())
                add_virtual({std::string(item.first), std::make_shared<DataTypeLowCardinality>(type)});
            else
                add_virtual({std::string(item.first), type});
        }
    }

    return desc;
}

static void addPathAndFileToVirtualColumns(
    Block & block,
    const String & path,
    size_t idx,
    const FormatSettings & format_settings,
    bool parse_hive_columns)
{
    if (block.has("_path"))
        block.getByName("_path").column->assumeMutableRef().insert(path);

    if (block.has("_file"))
    {
        auto pos = path.find_last_of('/');
        String file;
        if (pos != std::string::npos)
            file = path.substr(pos + 1);
        else
            file = path;

        block.getByName("_file").column->assumeMutableRef().insert(file);
    }


Review comment (refactor):
It seems this code resembles NamesAndTypesList::extractHivePartitionColumnsFromPath a lot. Can we reuse the function to get names and types list and after that call add_virtual in cycle?

Code after:
    VirtualColumnsDescription desc;

    auto add_virtual = [&](const NameAndTypePair & pair)
    {
        const auto & name = pair.getNameInStorage();
        if (storage_columns.has(name))
            return;

        const auto & type = pair.getTypeInStorage();
        desc.addEphemeral(name, type, "");
    };

    for (const auto & item : getCommonVirtualsForFileLikeStorage())
        add_virtual(item);

    if (!path.empty())
    {
        if (!partition_strategy.has_value())
            throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected partition strategy to be specified");

        /// If partition_stategy == none, we add hive columns, if present, to virtual columns.
        if (context->getSettingsRef()[Setting::use_hive_partitioning]
            && partition_strategy == PartitionStrategyFactory::StrategyType::NONE)
        {
            auto hive_columns = HivePartitioningUtils::extractHivePartitionColumnsFromPath(storage_columns, path, format_settings, context);
            for (const auto & column : hive_columns)
                add_virtual(column);
        }
    }

    return desc;
}

static void addPathAndFileToVirtualColumns(
    Block & block,
    const String & path,
    size_t idx,
    const FormatSettings & format_settings,
    bool parse_hive_columns)
{
    if (block.has("_path"))
        block.getByName("_path").column->assumeMutableRef().insert(path);

    if (block.has("_file"))
    {
        auto pos = path.find_last_of('/');
        String file;
        if (pos != std::string::npos)
            file = path.substr(pos + 1);
        else
            file = path;