- 数据库
- 关系型数据库
- 嵌入式数据库
- 密码学
【免费下载链接】sqlcipher
SQLCipher is a standalone fork of SQLite that adds 256 bit AES encryption of database files and other security features.
本篇指南以 SQLCipher 仓库
ext/misc/目录中的官方文档为核心,系统讲解该目录下 CSV 虚拟表、generate_series、ZIP 归档读写、unionvtab/swarmvtab 分库虚拟表等轻量级可加载扩展的实现原理与实战用法。读完本文,你将掌握如何编译、加载这些扩展,理解每个扩展的入口函数、虚拟表机制与典型 SQL 调用方式,并能直接在本仓库源码中定位对应实现。
一、ext/misc:一个"单文件可加载扩展"的工具箱
ext/misc/README.md是 SQLCipher 仓库(SQLite 的一个独立分支,增加了 256 位 AES 数据库文件加密)中"杂项扩展"目录的官方说明。它的定位非常明确:该目录存放了一批小型的、可加载的 SQLite 扩展,每个扩展都由单个 C 源文件实现,并在文件头部注释中给出完整的功能描述。
从源码结构看,这批扩展可分为三类:
- 虚拟表类:
csv.c、series.c、unionvtab.c、zipfile.c,以及目录中未被 README 单独列出但同样存在的amatch.c、closure.c、completion.c、fileio.c、fuzzer.c、spellfix.c、templatevtab.c、vtablog.c等; - SQL 函数类:
rot13.c、shathree.c、sha1.c,以及base64.c、base85.c、decimal.c、ieee754.c、percentile.c、regexp.c、uuid.c等; - 库/工具类:
dbdump.c(近似实现命令行.dump的 C 库)、appendvfs.c、cksumvfs.c、memstat.c、vfslog.c等 VFS 层组件。
所有扩展都遵循 SQLite 可加载扩展的标准约定:以#include "sqlite3ext.h"+SQLITE_EXTENSION_INIT1开头,导出sqlite3_<扩展名>_init入口函数(如 csv.c 中的sqlite3_csv_init)。编译与加载的通用方法请参考 SQLite 官方 loadable extensions 文档(sqlite.org/loadext.html),下文将给出基于本仓库的具体命令。
二、csv.c:用虚拟表直接查询 CSV 文件
csv.c 实现了一个用于读取逗号分隔值(CSV)文件的虚拟表,是"用 SQL 查询文件"最直接的例子。
2.1 基本用法
.load ./csv -- 在 sqlite3 命令行中加载扩展 CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME); SELECT * FROM csv;- 默认情况下,列被命名为
c1、c2、c3……,列数由 CSV 首行推断; - 通过
columns=N参数可显式指定列数; - 通过
schema=参数可用自定义CREATE TABLE语句定义列名与类型; - 通过
data=参数可直接把 CSV 文本作为字符串传入,无需文件。
2.2 带自定义 schema 的示例
CREATE VIRTUAL TABLE temp.csv2 USING csv( filename = '../http.log', schema = 'CREATE TABLE x(date,ipaddr,url,referrer,userAgent)' );2.3 源码实现要点
从源码结构看,csv 虚拟表的核心是一个CsvReader状态机(csv.c):它维护输入文件流、字段文本缓冲区、当前行号与缓冲读取位置,按字段为单位解析引号转义、逗号分隔与换行。模块还定义了CSV_MXERR 200(错误消息上限)与CSV_INBUFSZ 1024(输入缓冲大小)。若以-DSQLITE_TEST编译,模块还会启用专用于虚拟表测试的调试特性。仓库的 test/csv01.test 覆盖了该扩展的核心场景,包括参数缺省、schema=/columns=/data=组合等。
三、series.c:generate_series 表值函数
series.c 实现 PostgreSQL 风格的generate_series()表值函数,是"用虚拟表实现表值函数"的教科书级模板。
3.1 行为语义
其内部等价于如下虚拟表定义:
CREATE TABLE generate_series( value, -- 输出列,rowid 是该列的别名 start HIDDEN, -- 起始值(必填) stop HIDDEN, -- 结束值(默认 4294967295,即 0xffffffff) step HIDDEN -- 步长(默认 1,0 视为 1) );函数参数会被翻译为对隐藏列的等值约束,例如下面两对查询完全等价:
SELECT * FROM generate_series(0,100,5); SELECT * FROM generate_series WHERE start=0 AND stop=100 AND step=5;3.2 典型调用
SELECT * FROM generate_series(0,100,5); -- 0,5,10,...,95,100,共 21 行 SELECT * FROM generate_series(0,100); -- 0..100,步长 1,共 101 行 SELECT * FROM generate_series(20) LIMIT 10; -- 20..29,共 10 行 SELECT * FROM generate_series(0,-100,-5); -- 0,-5,...,-100,共 21 行 SELECT * FROM generate_series(0,-1); -- 空序列3.3 查询优化原理
该实现将xCreate置为 NULL,因此无法通过CREATE VIRTUAL TABLE ... USING generate_series显式创建,而是始终可用的"无名虚拟表"。xBestIndex会寻找对隐藏列start/stop/step的等值约束:
- 命中
start与stop时返回较小代价,鼓励查询规划器优先确定序列边界; - 缺失边界时使用默认值 0 / 4294967295 / 1;
- 2024-08-22 起(见 series.c 头注释),
xBestIndex还识别对value列的等值与不等值约束并将其作为序列范围的附加边界,因此:SELECT value FROM generate_series($SA,$EA) WHERE value BETWEEN $SB AND $EB;逻辑上等价于
generate_series(max($SA,$SB), min($EA,$EB))。
generate_series的约束边界仅限有符号 64 位整数,相关行为在 test/tabfunc01.test 等测试中有覆盖。
四、rot13.c:自定义 SQL 函数的最小模板
rot13.c 实现了极简单的rot13()替换函数,官方文档明确推荐它作为编写新自定义 SQL 函数的最佳起点模板。
4.1 实现要点
核心是一个 10 行左右的单字符转换函数(rot13.c):对a-z/A-Z的 ASCII 字母向后旋转 13 位并回绕,非字母字符保持不变,因此rot13(rot13(X)) == X恒成立。SQL 层函数rot13func遵循标准sqlite3_context/sqlite3_value约定:NULL 输入返回 NULL;短文本使用栈上 100 字节临时缓冲,长文本才走sqlite3_malloc64堆分配,避免频繁小分配。此外它还注册了rot13排序序列(collating sequence),使x = y COLLATE rot13等价于对rot13(x)与rot13(y)做二进制比较。
4.2 模板价值
从该文件可以学到一个完整 SQL 函数扩展需要的全部骨架:SQLITE_EXTENSION_INIT1初始化宏、参数数量校验、类型检查、内存管理与sqlite3_result_text结果回传——这些正是编写任何自定义 SQL 函数(包括 SQLCipher 场景下对加密字段做应用层变换)的通用范式。
五、shathree.c:sha3 / sha3_query 哈希函数
shathree.c 按 NIST FIPS 202 SHA-3 标准实现了三个 SQL 函数:
sha3(X, SIZE):对输入 X 计算 SHA3 哈希。文本按 UTF-8 字节、BLOB 按原始二进制、数字先转 UTF-8 文本再哈希;SIZE可选,缺省为 256,可取 224 / 256 / 384 / 512;sha3_agg(Y, SIZE):聚合函数,对全部 Y 输入求哈希。因顺序影响结果,官方建议配合ORDER BY使用;各数据类型被编码为带类型前缀的字节序列(如I+8 字节大端整数、Tnnn:+文本、Bnnn:+BLOB、N表示 NULL),因此sha3(1) = sha3('1')之类的恒等式成立(详见 shathree.c 头注释);sha3_query(Z, SIZE):执行 Z 中 SQL 语句产生的所有查询,对每行结果额外加前缀R后哈希,可用于对查询结果集做完整性校验。
该文件命名为shathree.c而非sha3.c,是因为 SQLite 默认入口点名称基于源文件名去掉数字生成——若叫sha3.c会与此前sha1.c扩展的入口点冲突(README 与源码注释均说明了这一点)。文件头部还给出了一组可直接验证的恒等式,例如:
SELECT sha3('hello') = sha3(x'68656c6c6f'); WITH a(x) AS (VALUES('xyzzy')) SELECT sha3_agg(x) = sha3('T5:xyzzy') FROM a;六、unionvtab.c 与 swarmvtab.c:跨库虚拟表
unionvtab.c 同时实现unionvtab与swarmvtab两个虚拟表,核心能力是把一张逻辑大表横向切分存储到多个数据库文件,再通过单一虚拟表只读访问。二者对源表的要求相同:
- 必须是 rowid 表(不能是虚拟表、WITHOUT ROWID 表或视图);
- 各表列集合、顺序与声明类型完全一致;
- 不允许有用户自定义的
_rowid_列; - 各表必须持有互不重叠的 rowid 区间。
区别在于:unionvtab要求所有源表位于主库或用户 ATTACH 的库中;swarmvtab则允许源表位于磁盘上任意数据库文件,由实现自动打开/关闭文件,且支持按需挂载(attach on demand)。
6.1 unionvtab 创建方式
CREATE VIRTUAL TABLE <name> USING unionvtab(<sql-statement>);该 SQL 语句在虚拟表每次创建或打开时执行,为每个源表返回一行,每行四列:所在数据库名(main/temp/ATTACH 名,或 NULL 表示按常规方式全库查找)、表名、该表可能存储的最小 rowid、最大 rowid。
6.2 swarmvtab 新旧两种语法
旧语法:
CREATE VIRTUAL TABLE <name> USING swarmvtab(<sql-statement>, <callback>);其中首列必须是可打开源库文件的路径或 URI;callback可选,当文件尚不存在时会被调用。
新语法:
CREATE VIRTUAL TABLE <name> USING swarmvtab( <sql-statement> [, <options>] );合法选项包括:missing=<udf>(文件缺失时的回调函数)、openclose=<udf>、maxopen=<integer>(最多同时打开的文件数)以及任意<sql-parameter>=<text-value>。SQL 语句除旧语法的 4 列外,还可返回第 5 列 "context" 文本(供回调使用)。
仓库中 test/unionvtab.test、test/unionvtabfault.test 与 test/swarmvtab.test、test/swarmvtab2.test、test/swarmvtab3.test 提供了完整的分库、按需打开与故障注入测试。
七、zipfile.c:可读可写的 ZIP 归档虚拟表
zipfile.c 提供一个能读取并写入 ZIP 归档文件的虚拟表。典型用法:
SELECT name, sz, datetime(mtime,'unixepoch') FROM zipfile($filename);当前实现的明确限制(源码头注释列出,zipfile.c):
- 不支持加密;
- 不支持跨多文件(spanning)归档;
- 不支持 zip64 扩展;
- 仅支持 zlib 的 inflate/deflate 压缩方法。
实现依赖 zlib 库,且与 CLI 的sqlite3_stdio.h模块配合时可复用其fopen定义;若未包含该头文件,则自行定义sqlite3_fopen(zipfile.c)。相关功能在 test/zipfile.test、test/zipfile2.test、test/zipfilefault.test 中验证。
八、dbdump.c:可嵌入的 .dump 等价库
dbdump.c不是可加载扩展,而是一个 C 语言库,提供对命令行.dump命令的近似等价实现:
int sqlite3_db_dump( sqlite3 *db, /* 数据库连接 */ const char *zSchema, /* 模式名:main / temp / 任意 ATTACH 库 */ const char *zTable, /* 为 NULL 时导出全部表,否则仅导出该表 */ void (*xCallback)(void*, const char*), /* 输出回调,签名兼容 fputs() */ void *pArg );其输出为可精确重建原库的 UTF-8 文本 SQL 语句,并保留 ROWID 值。回调签名特意设计为与fputs()兼容,便于直接接入输出流。若以-DDBDUMP_STANDALONE编译,文件会附带main()成为命令行工具,用法为dbdump <数据库文件> [schema] [table]。在仓库构建体系中,main.mk已将 dbdump 编为独立可执行目标(main.mk)。
九、编译、集成与在 SQLCipher 中使用
9.1 可加载扩展的标准编译路径
在 SQLCipher 仓库中,扩展编译进 CLI/库的方式已固化于 main.mk:
- main.mk、main.mk、main.mk、main.mk 将
csv.c、series.c、unionvtab.c、zipfile.c等列入 CLI 或核心库的编译源; - main.mk 将
series.c、shathree.c、sha1.c编译进测试构建; - main.mk 在另一组构建目标中同样引入
series.c、sha1.c、shathree.c、zipfile.c。
即:这些扩展既可随构建产物静态集成,也可单独编译为.so/.dll动态加载(sqlite3 命令行下使用.load ./csv等命令)。由于 SQLCipher 是 SQLite 的加密分支,其可加载扩展机制与上游一致,唯一需要注意的是扩展需链接到 SQLCipher 提供的sqlite3API 之上(编译时使用本仓库 src/sqlite3ext.h 与 src/sqlcipher.h 导出的接口)。
9.2 通用加载流程(适用于任一扩展)
# 编译单个扩展(以 rot13 为例) gcc -O2 -fPIC -shared ext/misc/rot13.c -o rot13.so # 在 sqlite3 命令行中加载并使用 sqlite3 test.db sqlite> .load ./rot13 sqlite> SELECT rot13('Hello, World!');十、总结:从文档到源码的完整阅读路径
ext/misc/README.md篇幅虽短,却精准勾勒出这批扩展的设计哲学——单文件、头注释即文档、以虚拟表和自定义函数两种机制扩展 SQL。在本仓库中,每个条目都能找到对应的完整实现与测试证据:
| README 条目 | 实现文件 | 仓库内测试 |
|---|---|---|
| CSV 虚拟表 | ext/misc/csv.c | test/csv01.test |
| 近似 .dump 的库 | ext/misc/dbdump.c | main.mk 独立目标 |
| JSON 处理(已内置于 amalgamation) | 核心实现位于 src/json.c | test/json 目录 |
| rot13 函数模板 | ext/misc/rot13.c | — |
| generate_series 虚拟表 | ext/misc/series.c | test/tabfunc01.test |
| sha3 系列函数 | ext/misc/shathree.c | — |
| unionvtab / swarmvtab | ext/misc/unionvtab.c | test/unionvtab.test、test/swarmvtab.test |
| ZIP 归档虚拟表 | ext/misc/zipfile.c | test/zipfile.test、test/zipfile2.test |
对于想深入 SQLCipher 扩展机制、或需要为加密数据库编写自定义 SQL 函数与虚拟表的开发者而言,ext/misc/是仓库中最值得研读的入门区:先读每个文件头部的注释(即"扩展自带文档"),再结合xBestIndex、sqlite3_context等接口源码,即可快速掌握 SQLite/SQLCipher 扩展开发的完整链路。
- 数据库
- 关系型数据库
- 嵌入式数据库
- 密码学
【免费下载链接】sqlcipher
SQLCipher is a standalone fork of SQLite that adds 256 bit AES encryption of database files and other security features.
相关推荐
Pyrite64骨骼蒙皮实战教程:6条单骨权重规则与Blender绑定建议
Pyrite64骨骼蒙皮实战教程:6条单骨权重规则与Blender绑定建议 Pyrite64 是一款基于 libdragon 与 tiny3d 构建的 N64
Akka Classic Extensions 扩展机制完全指南:从自定义扩展到配置加载与库扩展
Akka Classic Extensions 扩展机制完全指南:从自定义扩展到配置加载与库扩展 Akka Extensions 是 Akka 提供的官方扩展机
后端并发编程异步编程Apache Druid 扩展加载完全指南:core extensions、contrib extensions 与 classpath 加载机制
Apache Druid 扩展加载完全指南:core extensions、contrib extensions 与 classpath 加载机制 导读 Apa
数据库数据分析OLAP大数据实时分析数据仓库后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考