Repository: ClickHouse/ClickHouse
File: src/Dictionaries/IPAddressDictionary.cpp (C++)

Code before:
            key_mask_column->insertValue(mask_column[row]);
        }
        return {std::move(key_ip_column), std::move(key_mask_column)};
    }

    const auto * ipv6_col = std::get_if<IPv6Container>(&ip_column);

    auto key_ip_column = ColumnFixedString::create(IPV6_BINARY_LENGTH);
    auto key_mask_column = ColumnVector<UInt8>::create();

    for (size_t row : collections::range(0, row_idx.size()))
    {
        const char * data = reinterpret_cast<const char *>(getIPv6FromOffset(*ipv6_col, row));
        key_ip_column->insertData(data, IPV6_BINARY_LENGTH);
        key_mask_column->insertValue(mask_column[row]);
    }

    return {std::move(key_ip_column), std::move(key_mask_column)};
}

template <typename KeyColumnType, bool IsIPv4>
static auto keyViewGetter()
{
    return [](const Columns & columns, const std::vector<DictionaryAttribute> & dictonary_key_attributes)
    {
        const auto & key_attribute = dictonary_key_attributes.front();
        if (!isString(key_attribute.type))
            throw Exception(ErrorCodes::BAD_ARGUMENTS,
                "Key attribute '{}' of ip_trie dictionary must be of type String, got {}",
                key_attribute.name,
                key_attribute.type->getName());

        auto column = ColumnString::create();
        const auto & key_ip_column = assert_cast<const KeyColumnType &>(*columns.front());
        const auto & key_mask_column = assert_cast<const ColumnVector<UInt8> &>(*columns.back());
        char buffer[48];
        for (size_t row : collections::range(0, key_ip_column.size()))
        {
            UInt8 mask = key_mask_column.getElement(row);
            size_t str_len;
            if constexpr (IsIPv4)
                str_len = formatIPWithPrefix(reinterpret_cast<const unsigned char *>(&key_ip_column.getElement(row)), mask, true, buffer);
            else
                str_len
                    = formatIPWithPrefix(reinterpret_cast<const unsigned char *>(key_ip_column.getDataAt(row).data()), mask, false, buffer);
            column->insertData(buffer, str_len);
        }
        return ColumnsWithTypeAndName{
            ColumnWithTypeAndName(std::move(column), std::make_shared<DataTypeString>(), key_attribute.name)};
    };
}

Review comment (bug):
Why don't we validate the key type in create_layout? That way it would fail at load time and give a clearer message?

We could add a similar check there:

```
  const auto & key_type = dict_struct.key->front().type;                                                                                   
  if (!isString(key_type))                                                                                                                 
      throw Exception(ErrorCodes::BAD_ARGUMENTS,                                                                                           
          "Key attribute of ip_trie dictionary must be of type String, got {}",
          key_type->getName());
```

Code after:
            key_mask_column->insertValue(mask_column[row]);
        }
        return {std::move(key_ip_column), std::move(key_mask_column)};
    }

    const auto * ipv6_col = std::get_if<IPv6Container>(&ip_column);

    auto key_ip_column = ColumnFixedString::create(IPV6_BINARY_LENGTH);
    auto key_mask_column = ColumnVector<UInt8>::create();

    for (size_t row : collections::range(0, row_idx.size()))
    {
        const char * data = reinterpret_cast<const char *>(getIPv6FromOffset(*ipv6_col, row));
        key_ip_column->insertData(data, IPV6_BINARY_LENGTH);
        key_mask_column->insertValue(mask_column[row]);
    }

    return {std::move(key_ip_column), std::move(key_mask_column)};
}

template <typename KeyColumnType, bool IsIPv4>
static auto keyViewGetter()
{
    return [](const Columns & columns, const std::vector<DictionaryAttribute> & dictonary_key_attributes)
    {
        const auto & key_attribute = dictonary_key_attributes.front();
        auto column = ColumnString::create();
        const auto & key_ip_column = assert_cast<const KeyColumnType &>(*columns.front());
        const auto & key_mask_column = assert_cast<const ColumnVector<UInt8> &>(*columns.back());
        char buffer[48];
        for (size_t row : collections::range(0, key_ip_column.size()))
        {
            UInt8 mask = key_mask_column.getElement(row);
            size_t str_len;
            if constexpr (IsIPv4)
                str_len = formatIPWithPrefix(reinterpret_cast<const unsigned char *>(&key_ip_column.getElement(row)), mask, true, buffer);
            else
                str_len
                    = formatIPWithPrefix(reinterpret_cast<const unsigned char *>(key_ip_column.getDataAt(row).data()), mask, false, buffer);
            column->insertData(buffer, str_len);
        }
        return ColumnsWithTypeAndName{
            ColumnWithTypeAndName(std::move(column), std::make_shared<DataTypeString>(), key_attribute.name)};
    };
}

Pipe IPAddressDictionary::read(const Names & column_names, size_t max_block_size, size_t num_streams) const
{
    const bool is_ipv4 = std::get_if<IPv4Container>(&ip_column) != nullptr;

    auto key_columns = getKeyColumns();