Repository: ClickHouse/ClickHouse
File: src/Columns/ColumnUnique.h (C/C++)

Code before:
template <typename ColumnType>
void ColumnUnique<ColumnType>::collectSerializedValueSizes(PaddedPODArray<UInt64> & sizes, const UInt8 * is_null, const IColumn::SerializationSettings * settings) const
{
    /// nullable is handled internally.
    chassert(is_null == nullptr);
    if (IColumn::empty())
        return;

    if (is_nullable)
        column_holder->collectSerializedValueSizes(sizes, assert_cast<const ColumnUInt8 &>(*nested_null_mask).getData().data(), settings);
    else
        column_holder->collectSerializedValueSizes(sizes, nullptr, settings);
}

template <typename ColumnType>
std::string_view ColumnUnique<ColumnType>::serializeValueIntoArena(
    size_t n, Arena & arena, char const *& begin, const IColumn::SerializationSettings * settings) const
{
    if (is_nullable)
    {
        static constexpr auto s = sizeof(UInt8);

        auto * pos = arena.allocContinue(s, begin);
        UInt8 flag = (n == getNullValueIndex() ? 1 : 0);
        unalignedStore<UInt8>(pos, flag);

        if (n == getNullValueIndex())
            return std::string_view(pos, s);

        auto nested_ref = column_holder->serializeValueIntoArena(n, arena, begin, settings);

        /// serializeValueIntoArena may reallocate memory. Have to use ptr from nested_ref.data and move it back.
        return std::string_view(nested_ref.data() - s, nested_ref.size() + s);
    }


    return column_holder->serializeValueIntoArena(n, arena, begin, settings);
}

template <typename ColumnType>
char * ColumnUnique<ColumnType>::serializeValueIntoMemory(size_t n, char * memory, const IColumn::SerializationSettings * settings) const
{
    if (is_nullable)
    {
        UInt8 flag = (n == getNullValueIndex() ? 1 : 0);
        unalignedStore<UInt8>(memory, flag);
        ++memory;

        if (n == getNullValueIndex())
            return memory;
    }

Review comment (suggestion):
Currently, the types that `ColumnUnique` supports cannot return `std::nullopt`. I guess this might be better because if in the future `ColumnUnique` expands supported types, this will not break.

Code after:

template <typename ColumnType>
void ColumnUnique<ColumnType>::collectSerializedValueSizes(PaddedPODArray<UInt64> & sizes, const UInt8 * is_null, const IColumn::SerializationSettings * settings) const
{
    /// nullable is handled internally.
    chassert(is_null == nullptr);
    if (IColumn::empty())
        return;

    if (is_nullable)
        column_holder->collectSerializedValueSizes(sizes, assert_cast<const ColumnUInt8 &>(*nested_null_mask).getData().data(), settings);
    else
        column_holder->collectSerializedValueSizes(sizes, nullptr, settings);
}

template <typename ColumnType>
std::optional<size_t> ColumnUnique<ColumnType>::getSerializedValueSize(
    size_t n, const IColumn::SerializationSettings * settings) const
{
    if (is_nullable)
    {
        if (n == getNullValueIndex())
            return 1;
        auto nested_size = column_holder->getSerializedValueSize(n, settings);
        if (!nested_size)
            return std::nullopt;
        return 1 + *nested_size;
    }
    return column_holder->getSerializedValueSize(n, settings);
}

template <typename ColumnType>
std::string_view ColumnUnique<ColumnType>::serializeValueIntoArena(
    size_t n, Arena & arena, char const *& begin, const IColumn::SerializationSettings * settings) const
{
    if (is_nullable)
    {
        static constexpr auto s = sizeof(UInt8);

        auto * pos = arena.allocContinue(s, begin);
        UInt8 flag = (n == getNullValueIndex() ? 1 : 0);
        unalignedStore<UInt8>(pos, flag);

        if (n == getNullValueIndex())
            return std::string_view(pos, s);

        auto nested_ref = column_holder->serializeValueIntoArena(n, arena, begin, settings);

        /// serializeValueIntoArena may reallocate memory. Have to use ptr from nested_ref.data and move it back.
        return std::string_view(nested_ref.data() - s, nested_ref.size() + s);
    }