来源:https://github.com/duckdb/duckdb/blob/main/CLAUDE.md
CLAUDE.md
该文件为 Claude Code (claude.ai/code) 在使用此代码仓库时提供指导。
概述
DuckDB 是一个高性能的分析数据库系统,旨在快速、可靠、可移植且易于使用。它是一个进程内 SQL OLAP 数据库管理系统,具有丰富的 SQL 方言、向量化执行引擎和列式存储格式。
构建命令
基本构建
bash
make debug # 构建带有 sanitizer 和断言的调试版本
make reldebug # 构建带有调试符号的优化发布版本
FORCE_DEBUG=1 make relassert # 构建带有 sanitizer 和断言的优化版本
测试
运行测试
bash
build/reldebug/test/unittest # 快速单元测试
运行特定测试
bash
# 运行特定的测试文件
build/reldebug/test/unittest test/sql/order/test_limit.test
# 运行所有测试(包括慢速测试)
build/reldebug/test/unittest "*"
建议使用 make reldebug 和 build/reldebug/test/unittest,除非有充分的理由使用调试版本------调试版本比 reldebug 版本慢得多。
测试文件格式
测试使用 sqllogictest 格式(.test 文件)。结构示例:
sql
# name: test/sql/order/test_limit.test
# description: 测试 LIMIT 关键字
# group: [order]
statement ok
CREATE TABLE test (a INTEGER, b INTEGER);
query I
SELECT a FROM test LIMIT 1
----
11
statement error
SELECT a FROM test LIMIT a
----
<REGEX>:Binder Error:.*not found.*
测试指令:
statement ok- 语句应成功执行statement error- 语句应失败query I- 返回 INTEGER 列的查询query II- 返回两列的查询----- 分隔查询和预期结果<REGEX>:- 预期的错误消息模式require-env VAR- 测试需要环境变量
慢速测试应使用 .test_slow 扩展名而不是 .test。
代码格式化
bash
make format-fix # 格式化所有代码(clang-format + black)
确保在提交前运行格式化。
架构
查询执行管道
SQL 字符串
↓
[解析器] - 使用 PEG 解析器将 SQL 解析为 AST
↓
SQLStatement 树(ParsedExpression, TableRef 对象)
↓
[规划器/绑定器] - 将符号绑定到目录,创建逻辑计划
↓
逻辑计划(带有绑定表达式的 LogicalOperator 树)
↓
[优化器] - 应用基于规则和基于成本的优化
↓
优化后的逻辑计划
↓
[物理计划生成器] - 转换为物理操作符
↓
物理计划(PhysicalOperator 树)
↓
[执行器] - 以向量化、并行管道方式执行
↓
结果
核心组件
解析器 (src/parser/)
- 将 SQL 字符串转换为抽象语法树
- 使用基于 PEG 的解析器
- 语法位于
*.gram文件中,使用scripts/build_grammar.sh生成 - 输出:
SQLStatement、ParsedExpression、TableRef对象 - 关键子目录:
expression/、statement/、tableref/、peg/
关于添加新语法的更多详细信息,请参阅 src/parser/peg/README.md 中的 README。
每个新的语法规则必须有一个对应的转换器规则,位于 peg/transformer。
规划器 (src/planner/)
- 将符号绑定到目录条目并解析类型
- 创建逻辑查询执行计划
- 关键类:
Binder、LogicalOperator、绑定的Expression类型 - 子目录:
binder/、expression/、subquery/
优化器 (src/optimizer/)
- 在不改变语义的情况下转换逻辑计划
- 应用谓词下推、连接顺序优化、表达式重写等
- 子目录:
join_order/、statistics/、rule/、pushdown/
执行引擎 (src/execution/)
- 将逻辑计划转换为物理计划并执行
- 基于推模型的向量化执行模型
- 以批次(通常为 2048 行)处理数据
- 关键子目录:
operator/(扫描、连接、过滤、聚合等)、expression_executor/
存储 (src/storage/)
- 管理持久数据存储和缓冲区管理
- 基于块的存储,支持压缩
- 包含用于持久性的预写日志
- 子目录:
buffer/、compression/、checkpoint/、table/
目录 (src/catalog/)
- 管理表、模式、函数、类型等的元数据
- 数据库元数据的唯一可信源
- 关键类:
Catalog、CatalogEntry、SchemaCatalogEntry
事务管理器 (src/transaction/)
- 支持 MVCC 的 ACID 事务管理
- 协调数据的并发访问
- 关键文件:
transaction_manager.cpp、undo_buffer.cpp、wal_write_state.cpp
并行执行 (src/parallel/)
- 具有任务调度的多线程执行
- 基于管道的并行性
- 关键文件:
executor.cpp、pipeline_executor.cpp、task_scheduler.cpp
函数 (src/function/)
- 内置函数实现
- 类型:
scalar/、aggregate/、table/、window/、pragma/
目录结构
/duckdb
├── src/ # 核心 C++ 源代码
│ ├── include/duckdb/ # 公共头文件
│ ├── parser/ # SQL 解析
│ ├── planner/ # 逻辑规划
│ ├── optimizer/ # 查询优化
│ ├── execution/ # 物理执行
│ ├── storage/ # 数据存储
│ ├── catalog/ # 元数据管理
│ ├── transaction/ # 事务管理
│ ├── parallel/ # 并行化
│ ├── function/ # 内置函数
│ ├── common/ # 共享实用程序和类型
│ └── main/ # 数据库/连接管理
├── extension/ # 树内扩展(parquet, json, icu 等)
├── test/ # 测试框架和测试用例
│ ├── sql/ # SQL 回归测试(.test 文件)
│ └── api/ # C/C++ API 测试
├── tools/ # 语言绑定(pythonpkg, shell 等)
├── benchmark/ # 基准测试套件(TPC-H, TPC-DS 等)
├── scripts/ # 构建和实用脚本
└── third_party/ # 第三方依赖
扩展
DuckDB 支持两种类型的扩展:
树内扩展 (位于 extension/ 目录):
- 扩展位于树内
- 完整列表见
.github/config/in_tree_extensions.cmake - 代码可以直接编辑并提交到仓库。
树外扩展:
- 扩展位于独立的 git 仓库中
- 完整列表见
.github/config/out_of_tree_extensions.cmake - 当需要更改时,必须在存储于
.github/patches的补丁文件中进行
使用扩展构建:
bash
# 构建所有扩展
BUILD_ALL_EXT=1 make
# 构建特定扩展
DUCKDB_EXTENSIONS='json;icu' make
关键开发模式
数据流
- 向量化处理:数据以列式批次处理(非逐行),通常每批 2048 行
- Vector 类:表示一个列式数据批次
- ColumnBinding :在整个规划和执行过程中用于列的唯一标识符
(table_index, column_index)
表达式类型
ParsedExpression- 来自解析器,未绑定Expression- 已绑定并包含类型信息ExpressionExecutor- 表达式的向量化执行
内存管理
- 优先使用
unique_ptr<T>表示独占所有权 - 仅在必要时使用
shared_ptr<T> optional_ptr<T>表示可为空的引用,reference<T>表示非空引用- 永远不要使用原始指针
类型系统
LogicalType- 抽象数据类型表示src/function/cast_rules.cpp中的类型提升规则- 通过扩展系统支持自定义类型
常见模式
- 访问者模式 :用于树遍历(例如
LogicalOperatorVisitor、ExpressionIterator) - 工厂模式 :用于对象创建的
Deserialize()方法 - 类层次结构 :基类如
*Operator、*Entry、*Expression,带有类型化的子类
编码指南(要点)
C++ 风格
- 使用制表符进行缩进,使用空格进行对齐
- 行不应超过 120 列(运行格式化工具)
- 使用
[u]int(8|16|32|64)_t而不是int、long等 - 使用
idx_t而不是size_t表示偏移量/索引/计数 - 对非平凡对象使用
const引用 - 尽可能使用 C++11 基于范围的 for 循环
- 对 if 语句和循环始终使用花括号
- 永远不要使用
const_cast
命名约定
- 文件 :
snake_case(例如abstract_operator.cpp) - 类型 :
PascalCase(例如LogicalOperator) - 变量 :
snake_case(例如chunk_size) - 函数 :
PascalCase(例如GetChunk)
类布局
cpp
class MyClass {
public:
MyClass();
int my_public_variable;
public:
void MyFunction();
private:
void MyPrivateFunction();
private:
int my_private_variable;
};
错误处理
- 对终止查询的错误(解析错误、表未找到、内存不足等)使用异常
- 对查询期间可恢复的错误使用返回值
- 对编程错误使用
D_ASSERT(永远不应由用户输入触发) - 大量使用断言,并附上清晰的注释
测试要求
- 优先使用 sqllogictest 框架(
.test文件)而不是 C++ 测试 - 使用不同类型(数字、字符串、嵌套类型)进行测试
- 测试意外/不正确的用法,而不仅仅是正确路径
- 慢速测试应使用
.test_slow扩展名 - 提交 PR 前必须通过所有测试(
make allunit) - 目标是高代码覆盖率
导航技巧
查找组件
- 入口点:
src/main/database.cpp(DatabaseInstance) - 查询执行协调器:
src/main/client_context.cpp - SQL 解析:
src/parser/parser.cpp - 逻辑规划:
src/planner/binder/query_planner.cpp - 优化编排:
src/optimizer/optimizer.cpp - 物理计划生成:
src/execution/physical_plan/physical_plan_generator.cpp - 执行编排:
src/parallel/executor.cpp
搜索代码库
- 使用
grep或ripgrep进行代码搜索 - 函数定义通常在
.cpp文件中 - 类声明在
src/include/duckdb/头文件中 - 测试用例按功能位于
test/sql/中
理解一个特性
- 在
test/sql/中找到测试用例以查看用法示例 - 从解析器 → 规划器 → 优化器 → 执行器跟踪
- 查找相应的
*Statement、*Operator、*Expression类 - 检查目录中的函数注册
修改生成的文件
有些文件是自动生成的。修改其源文件后,运行:
bash
make generate-files
这会重新生成:
- C API 绑定
- 函数注册
- 设置
- 序列化代码
- 存储信息
- 指标枚举
- 枚举实用程序
文档
- 主要文档:https://duckdb.org/docs/
- 开发文档:https://duckdb.org/dev/
- 构建指南:https://duckdb.org/docs/dev/building/overview
- 测试文档:https://duckdb.org/dev/testing
重要文件
Makefile- 主要构建配置CMakeLists.txt- CMake 配置CONTRIBUTING.md- 贡献指南test/README.md- 测试文档extension/extension_config.cmake- 扩展配置scripts/format.py- 代码格式化工具scripts/generate_*.py- 代码生成脚本
文件内容结束