ClickHouse v26.3.8.4-lts 变更深度解读:字符串搜索越界读取、全文索引兼容性与 Coalescing 合并树修复
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
v26.3.8.4-lts 是 ClickHouse 2026 年 LTS 分支的一个补丁版本,包含三项针对官方稳定版用户可见行为的 Bug Fix,覆盖字符串搜索函数、全文(文本)索引配置兼容性以及 Coalescing 合并树三类问题。本文以 官方变更记录 为主体,结合仓库源码逐项解析每个修复的背景、影响面与底层实现,帮助你判断升级必要性并做好验证。
版本概览
根据变更记录,本版本基线信息如下:
- 版本号:
v26.3.8.4-lts(commitf3c6e5a4d27) - 对比基准:
v26.3.7.8-lts(commit177c6aa7da1) - 修复类型:全部为 Bug Fix(官方稳定版中的用户可见错误行为)
三项修复分别由不同维护者提交并反向移植(backport)到 LTS 分支:
| 修复项 | 核心问题 | 关联提交/Issue |
|---|---|---|
| 字符串搜索越界读取 | needle 全为\0字节时越界读 | PR #102401,backport #102479 |
| 全文索引配置被误禁用 | compatibility低于 26.1 时文本索引设置失效 | PR #102422,backport #102456 |
| Coalescing 合并树 array 类型 | 合并树对数组类型的合并异常 | PR #102384,关闭 #89509,backport #102453 |
下文按修复项逐一展开。
修复一:字符串搜索函数对全零字节 needle 的越界读取
问题现象
countSubstrings、position等字符串搜索函数在查找“完全由\0(null byte)组成”的 needle(搜索子串)时,存在**越界读取(out-of-bounds read)**问题。这类问题在内存安全检查(如 AddressSanitizer)下可能触发报告,在特定数据布局下也可能导致不可预期的行为。
涉及的函数族
这些函数由 src/Functions/FunctionsStringSearch.h 统一实现,包括:
position(haystack, needle):返回子串出现的字节位置(从 1 开始,未找到返回 0)positionUTF8/positionCaseInsensitive/positionCaseInsensitiveUTF8:按码点或忽略大小写变体countSubstrings(haystack, needle):统计 needle 在 haystack 中的出现次数like/ilike/match等基于同样搜索原语的函数
countSubstrings的独立实现位于 src/Functions/countSubstrings.cpp 与 src/Functions/CountSubstringsImpl.h。
源码层面的边界处理
从 CountSubstringsImpl.h 可以看到,实现针对空 needle 已有显式防护。例如在vectorConstant路径中:
if (needle.empty()) return; /// Return all zeros; the entry checkpoint above already observed the deadline.在vectorVector路径中也有对应处理:
else if (0 == needle_size) { /// 0 already }而本修复针对的是非空但内容全部为\0的 needle。这类 needle 长度不为零,会进入搜索器(searcher)初始化与逐行扫描路径,问题正出现在这段扫描逻辑中——修复后确保了整个搜索路径(含countSubstrings、position及其大小写变体)对全零字节 needle 的读写都严格落在列数据边界内。
实战验证建议
升级到v26.3.8.4-lts后,可在本地使用如下查询验证该场景不再触发越界读取:
-- 构造全零字节 needle 的边界场景 SELECT countSubstrings(materialize('abc'), char(0, 0, 0)); SELECT position(materialize('abc'), char(0, 0, 0));配合ASAN_OPTIONS=...启动的 AddressSanitizer 构建可进一步确认无越界告警。仓库中的 gtest_functions_stress.cpp 等压力测试文件覆盖了字符串函数的边界输入组合,可作为回归验证参考。
修复二:全文(文本)索引设置不再被 compatibility 误禁用
问题背景
本修复解决的是设置(Settings)与兼容性(compatibility)机制的交互缺陷:当查询或会话的compatibility设置指向26.1 之前的版本时,以下三个全文索引相关设置会被错误地禁用:
enable_full_text_indexallow_experimental_full_text_indexuse_skip_indexes_on_data_read
这导致一个实际问题:SharedDatabaseCatalog在使用文本索引创建表时可能失败——因为底层索引设置被认为不可用。
设置定义与别名关系
在 src/Core/Settings.cpp 中可以看到enable_full_text_index的定义方式:
DECLARE_WITH_ALIAS(Bool, enable_full_text_index, true, R"( If set to true, allow using the text index. )", 0, allow_experimental_full_text_index) \也就是说,allow_experimental_full_text_index是enable_full_text_index的历史别名(实验性名称),二者指向同一个开关,默认值为true。它控制的是“是否允许使用文本索引(text index / inverted index)”。
另一个被误禁用的use_skip_indexes_on_data_read定义于 src/Core/Settings.cpp,默认true,控制读取数据时是否应用跳数索引(skip index)进行过滤。
SettingsQuirks 的兼容性调整机制
ClickHouse 用compatibility设置模拟旧版本行为,相关调整集中在 src/Core/SettingsQuirks.cpp。其中可以看到一个同族的文本索引设置也会在兼容模式下被强制关闭:
if (settings[Setting::query_plan_direct_read_from_text_index]) settings[Setting::query_plan_direct_read_from_text_index] = false; adjusted.emplace_back("query_plan_direct_read_from_text_index = 0");本次修复正是修正了这类兼容性“淬火”(quirk)逻辑中把文本索引设置一刀切禁用的行为,确保compatibility指向旧版本时,enable_full_text_index等设置仍保持有效,从而让SharedDatabaseCatalog能正常创建带文本索引的表。
文本索引周边设置一览
围绕全文索引,仓库还提供了若干配套开关(Settings.cpp),升级后可结合使用:
| 设置 | 默认值 | 作用 |
|---|---|---|
query_plan_direct_read_from_text_index | true | 查询计划中仅用倒排文本索引完成全文过滤 |
query_plan_optimize_count_from_text_index | true | 直接依据索引 posting-list 基数回答count(),需前者开启 |
query_plan_text_index_add_hint | true | 基于倒排索引构造附加谓词提示 |
text_index_hint_max_selectivity | 0.2 | 提示生效的最大选择率阈值 |
use_text_index_like_evaluation_by_dictionary_scan | true | 通过扫描索引词典加速%value%等 LIKE 模式 |
text_index_like_min_pattern_length | 4 | 走词典扫描的最小模式长度 |
文本索引的读取端实现见 src/Storages/MergeTree/MergeTreeReaderTextIndex.h,查询计划侧的过滤/裁剪逻辑位于 src/Processors/QueryPlan/ReadFromMergeTree.cpp。
修复三:Coalescing 合并树对 array 类型的修复
Coalescing 合并模式是什么
在 MergeTree 家族的合并参数中,MergingParams::Mode定义了多种合并语义,Coalescing是其中之一,其枚举定义位于 src/Storages/MergeTree/MergeTreeData.h:
Coalescing = 8,Coalescing 模式与 Summing 模式同族:它会在合并时把相邻行中相同键的数值列合并(coalesce)。在 src/Storages/MergeTree/MergeTreeData.cpp 中可以看到相关校验逻辑——columns_to_sum非空时要求模式必须是 Summing 或 Coalescing:
if (!columns_to_sum.empty() && mode != MergingParams::Summing && mode != MergingParams::Coalescing)该合并模式的排序合并在执行端由 src/Processors/Merges/CoalescingSortedTransform.h 中的CoalescingSortedTransform完成,它基于SummingSortedAlgorithm实现。
本次修复的内容
变更记录描述为“Coalescing merge tree fix for array type”,即该合并模式在处理Array(数组)类型列时存在缺陷,本版本对其进行了修正,并关闭了 issue #89509。从源码结构看,此类修复通常落在合并算法的类型分派与数值累加路径上(MergeTreeData.cpp 中 Summing/Coalescing 共用同一分支),涉及对列类型分支的边界补齐。
受影响的部署形态
如果你的表使用了基于 Coalescing 合并语义的 MergeTree 变体,并且表中包含Array(...)类型列,建议升级后对相关表执行一次OPTIMIZE TABLE ... FINAL并比对合并前后结果,以验证数据一致性。
升级建议与验证路径
- 升级到 v26.3.8.4-lts:在 LTS 分支内做补丁升级,风险面小,三项修复均为稳定版用户可见行为的缺陷修正。
- 验证版本:
SELECT version();应输出26.3.8.4及以上 LTS 版本。 - 重点回归场景:
- 含全零字节字符串的
countSubstrings/position查询(修复一); - 设置了
compatibility为 26.1 之前版本、且使用文本索引建表的SharedDatabaseCatalog场景(修复二); - 含
Array类型列、启用 Coalescing 合并语义的 MergeTree 表(修复三)。
- 含全零字节字符串的
本版本的完整变更条目可在 docs/changelogs/v26.3.8.4-lts.md 查看,更多历史版本的变更记录位于 docs/changelogs 目录;相关设置的默认值与说明可在 src/Core/Settings.cpp 中检索对应设置名进行核对。
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考