# DB Kernel Func Skill

> 数据库内核 SQL 内置函数合成（SQLite / PostgreSQL / DuckDB / ClickHouse）。 覆盖各库的函数注册入口与模式、四大开发规范（功能准确/代码集成/鲁棒性/内存安全）、 各库错误处理与内存管理 API、以及编译/测试命令。用于给数据库写 C/C++ 原生函数、 扩展 SQL 能力时。知识提炼自 SIGMOD 2026 DBCooker/OpenCook 论文与源码。

- Skill: `aresbit/db-kernel-func-skill` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add aresbit/db-kernel-func-skill`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aresbit/db-kernel-func-skill/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: aresbit (https://skillmd.com/u/aresbit)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aresbit/db-kernel-func-skill

---


# 数据库内核函数合成

给数据库内核（SQLite/PostgreSQL/DuckDB/ClickHouse）实现新的 SQL 内置函数，让它能被
SQL 语句直接调用。这是"repository-level code completion"——不是写个独立脚本，而是把
代码正确织入官方仓库的注册体系、内存模型、类型系统和构建流程。

## 核心纪律（来自 DBCooker 论文的实证发现）

1. **先查重，再动手**。写代码前先确认目标函数是否已存在，避免 duplicate symbol 错误。
   如果已有实现满足规格，不要重写，直接验证并收工。
2. **先定位入口点，别盲目搜文件**。通用编码 agent 有 63.7% 的时间浪费在文件搜索上；
   先搞清"这个函数该注册在哪、依赖哪些宏/辅助函数"，再写第一行。
3. **声明正确性优先**。81.76% 的合成错误是 declaration 相关（注册表项、头文件声明、
   函数签名），不是算法逻辑。先把注册和声明写对，逻辑反而不难。

## 各库注册入口与模式

| 数据库 | 语言 | 注册入口 | 模式 |
|---|---|---|---|
| SQLite | C | `FuncDef aBuiltinFunc[]`，`src/func.c` | `FUNCTION(name, nArg, flags, xFlags, funcPtr)` |
| PostgreSQL | C | `src/backend/utils/adt/*.c` + `pg_proc.dat` + `builtins.h` | `PG_FUNCTION_INFO_V1(name)` + `Datum name(PG_FUNCTION_ARGS)` |
| DuckDB | C++ | `ScalarFunctionSet` / `FunctionFactory`，`extension/` | `CreateScalarFunctionInfo` + 注册到 Catalog |
| ClickHouse | C++ | `FunctionFactory::instance()` | `registerFunction<FunctionX>()` |

SQLite 最小例子：`sign` 的计算逻辑写在 `signFunc`（`func.c` 内），通过
`FUNCTION(sign, 1, 0, 0, signFunc)` 注册到 `FuncDef aBuiltinFunc[]`，之后
`SELECT sign(x)` 即可用。

## 四大开发规范

**1. 功能准确（Functional Accuracy）**
只实现规格指定的行为，不引入额外功能。
- PostgreSQL：匹配既有 SQL 语义的 NULL 处理与类型强转。
- 不要顺手"优化"或加参数默认值，内核函数的行为会被无数下游查询依赖。

**2. 代码集成（Code Integration）**
识别所有需要改的文件、调用路径、API。注意数据库版本差异，遵循仓库的编码风格、
错误处理和日志约定。
- PostgreSQL 错误处理：`elog()` / `ereport()` / `errcode()`。
- ClickHouse 日志：`LOG_ERROR` / `LOG_WARNING` / `LOG_INFO`，遵循 C++ 风格。

**3. 鲁棒性（Robustness）**
主动覆盖边界：NULL 值、输入范围、类型转换、非法输入、溢出/下溢。
- PostgreSQL：`int8` 算术要防溢出；NULL 输入应传播为 NULL。
- ClickHouse：`Nullable` 列上的行为要明确；大整数不能意外回绕（wrap）。

**4. 内存与安全（Memory & Safety）**
防止未定义行为，不泄漏、不悬挂指针、不做不安全操作。
- PostgreSQL：在内存上下文里用 `palloc`/`pfree`；绝不返回指向 transient 缓冲区的指针。
- SQLite：`sqlite3_malloc` 的结果必须用 `sqlite3_free` 释放；使用前检查分配失败。

## 实现计划格式（Plan → Code）

先写实现计划，含有序步骤，每步：(1) 目标文件绝对路径 (2) 函数签名 (3) 步骤描述
(4) 代码骨架占位符 + 本库可用的 code elements。示例（PG 的 `text_substring`）：

```
/* Step 1: 初始化字符串编码与子串位置变量
   Potential code elements: pg_database_encoding_max_length(), Max(), Datum */
[ code to be filled ]

/* Step 2: 处理单字节编码 (eml == 1)
   Potential code elements: DatumGetTextPSlice(), pg_add_s32_overflow() */
[ code to be filled ]
```

实现函数时，参考其他数据库里相同/相似功能的实现（reference function），能少走弯路。

## 编译与测试命令

### SQLite
```bash
mkdir -p build && cd build
../configure && make sqlite3 -j$(nproc) && make tclextension -j$(nproc)
# 增量编译：cd build && make sqlite3
# 测试：cd build && make testfixture && ./testfixture ../test/func.test
```
函数相关测试文件：`func.test` ~ `func9.test`、`coalesce.test`、`window9.test` 等。

### DuckDB
```bash
make release -j$(nproc)          # 在 duckdb 根目录
# 测试：./build/release/test/unittest                          # 全量
#       ./build/release/test/unittest "[numeric]"              # 组
#       ./build/release/test/unittest test/sql/agg/xxx.test    # 单文件
```
解析 unittest 输出的 summary：`test cases: N | N passed | N failed | N skipped`。

### PostgreSQL
```bash
./configure --prefix=$INSTALL && make -j$(nproc) -s && make install
# 测试：make installcheck PGUSER=postgres PGPORT=5432
```
（需先 initdb + pg_ctl start 起实例。）

## 内核原理深度参考（本地 reference，随 skill 自带）

写函数不只是「填注册表项」，要理解它在内核执行上下文里的行为。这些课程笔记已复制进本 skill 的
`references/` 目录，写函数时直接读本地文件（相对路径，随 skill 打包分发），不依赖 skill 目录之外的任何外部路径。
遇到原理问题，按下面这张表定位到具体的 ch 文件：

| 写函数时的问题 | 查哪门课（本地 references/ 相对路径，精确到文件） |
|---|---|
| 标量/聚合函数在执行器里怎么被调用（火山/向量化/编译执行模型） | `references/query-opt/ch07_执行模型：火山、物化与向量化.md`、`references/15445/ch11_查询执行I.md`、`references/15445/ch12_查询执行II_并行.md` |
| 聚合函数状态在分组/排序里的传递、累加器生命周期 | `references/15445/ch09_排序与聚合.md` |
| 内存分配与 buffer pool 交互（大结果集别越界、别泄漏） | `references/15445/ch05_缓冲池.md` |
| NULL 传播语义、类型强转、函数重载解析 | `references/15445/ch02_高级SQL.md` |
| 函数并发安全（要不要加锁、与 MVCC/2PL 怎么配合） | `references/15445/ch15_并发控制理论.md`、`references/15445/ch16_两阶段锁.md`、`references/15445/ch17_时间戳排序.md`、`references/15445/ch18_多版本并发控制.md`、`references/transaction/ch04_两阶段锁协议.md`、`references/transaction/ch08_MVCC基础.md` |
| 崩溃恢复里函数副作用（WAL / ARIES 语义） | `references/15445/ch19_日志协议与方案.md`、`references/15445/ch20_崩溃恢复算法_ARIES.md` |
| 向量/相似度函数（距离度量、量化/图索引下的行为） | `references/vectordb/ch02_向量表示与相似度度量.md`、`references/vectordb/ch03_精确与近似最近邻搜索.md`、`references/vectordb/ch04_基于量化的索引.md`、`references/vectordb/ch05_基于图的索引.md`、`references/vectordb/ch06_过滤向量搜索与系统挑战.md` |
| 窗口/分析函数语义（frame、partition） | `references/15445/ch09_排序与聚合.md`、`references/duckdb-analytics/index.md` |
| 函数内联与代码生成（查询编译，tum-codegen 那套） | `references/tum-codegen/ch12_查询编译.md`、`references/query-opt/ch07_执行模型：火山、物化与向量化.md` |

要点：**先查原理再动手**。比如写聚合函数，先确认目标库的执行模型是火山还是向量化，
累加器在哪分配、怎么 reset，这决定函数签名和生命周期——比盲目照抄注册表项靠谱得多。

## 验证闭环

写完必须走三级验证，缺一不可：
1. **语法**：编译通过（各库的 compile 命令）。
2. **合规**：符合仓库风格与注册约定（宏、声明、命名）。
3. **语义**：跑函数相关测试，输出里 `0 errors out of` 才算过。

结论的置信度 = 验证走到哪一级。只编译过不算完成，测试没过就贴失败输出。

