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

Code before:
            left_mark = mid_mark + 1;
    }
    size_t end_mark = (left_mark == last_mark) ? left_mark : left_mark + 1;
    return index_granularity->getRowsCountInRange(current_mark, end_mark);
}


bool MergeTreeRangeReader::isCurrentRangeFinished() const
{
    return stream.isFinished();
}

static size_t getBytesInColumn(const IColumn & column)
{
    if (const auto * col_str = typeid_cast<const ColumnString *>(&column))
    {
        /// This function is used to estimate the number of bytes read from disk. For String column offsets might actually take
        /// more memory than chars, so blindly assuming that each offset takes 8 bytes might overestimate the actual bytes read.
        return col_str->getChars().size() + col_str->getOffsets().size() * getLengthOfVarUInt(col_str->getOffsets().back());
    }
    else if (const auto * col_sparse = typeid_cast<const ColumnSparse *>(&column))
    {
        /// Same logic as ColumnString for sparse columns.
        const auto & values = col_sparse->getValuesColumn();
        const auto & offsets = col_sparse->getOffsetsColumn();
        return !offsets.empty() ? getBytesInColumn(values) + offsets.size() * getLengthOfVarInt(offsets.getInt(offsets.size() - 1)) : 0;
    }
    else
    {
        return column.byteSize();
    }
}

static size_t getTotalBytesInColumns(const Columns & columns)
{
    size_t total_bytes = 0;
    for (const auto & column : columns)
    {
        if (column)
            total_bytes += getBytesInColumn(*column);
    }
    return total_bytes;
}

MergeTreeRangeReader::ReadResult MergeTreeRangeReader::startReadingChain(size_t max_rows, MarkRanges & ranges)
{
    ReadResult result(log);
    result.columns.resize(merge_tree_reader->getResultColumnCount());

    size_t current_task_last_mark = getLastMark(ranges);


Review comment (refactor):
The ternary operation with the empty check could be clearer. The logic mixes the empty check with the calculation in a way that makes it harder to understand the intent. Consider extracting the offset calculation or adding a comment explaining why the empty check is necessary.
```suggestion

        if (offsets.empty())
            return 0;

        /// Offsets are stored as VarInt; estimate their total size using the last offset's length.
        return getBytesInColumn(values)
            + offsets.size() * getLengthOfVarInt(offsets.getInt(offsets.size() - 1));
```

Code after:
            left_mark = mid_mark + 1;
    }
    size_t end_mark = (left_mark == last_mark) ? left_mark : left_mark + 1;
    return index_granularity->getRowsCountInRange(current_mark, end_mark);
}


bool MergeTreeRangeReader::isCurrentRangeFinished() const
{
    return stream.isFinished();
}

static size_t getBytesInColumn(const IColumn & column)
{
    if (const auto * col_str = typeid_cast<const ColumnString *>(&column))
    {
        /// This function is used to estimate the number of bytes read from disk. For String column offsets might actually take
        /// more memory than chars, so blindly assuming that each offset takes 8 bytes might overestimate the actual bytes read.
        return col_str->getChars().size() + col_str->getOffsets().size() * getLengthOfVarUInt(col_str->getOffsets().back());
    }
    else if (const auto * col_sparse = typeid_cast<const ColumnSparse *>(&column))
    {
        /// Same logic as ColumnString for sparse columns.
        const auto & values = col_sparse->getValuesColumn();
        const auto & offsets = col_sparse->getOffsetsColumn();

        if (offsets.empty())
            return 0;

        /// Offsets are stored as VarInt; estimate their total size using the last offset's length.
        return getBytesInColumn(values)
            + offsets.size() * getLengthOfVarInt(offsets.getInt(offsets.size() - 1));
    }
    else
    {
        return column.byteSize();
    }
}

static size_t getTotalBytesInColumns(const Columns & columns)
{
    size_t total_bytes = 0;
    for (const auto & column : columns)
    {
        if (column)
            total_bytes += getBytesInColumn(*column);
    }
    return total_bytes;
}

MergeTreeRangeReader::ReadResult MergeTreeRangeReader::startReadingChain(size_t max_rows, MarkRanges & ranges)