本文翻译自Architecture of SQLite https://www.sqlite.org/arch.html
介绍
本文档描述了SQLite库的体系结构。这里的信息对于那些想理解或修改SQLite内部工作的人很有用。 附近的图表显示了SQLite的主要组件以及它们如何进行互操作。 下面的文本解释了各种组件的角色。
Interface
大多数C语言接口都可以在源文件main.c、legacy.c和vdbeapi.c中找到,尽管有些例程分散在其他文件中,它们可以访问具有文件作用域的数据结构。sqlite3_get_table()例程在table.c中实现。sqlite3_mprintf()例程在printf.c中找到。sqlite3_complete()接口在complete.c中。TCL接口由tclsqlite.c实现。
为了避免名称冲突,SQLite库中的所有外部符号都以前缀sqlite3开头。那些用于外部使用的符号(换句话说,那些构成SQLite的API的符号)添加了下划线,因此以sqlite3开头。扩展api有时会在下划线之前添加扩展名;例如:sqlite3rbu或sqlite3session。
Tokenizer
当要计算包含SQL语句的字符串时,它首先被发送到tokenizer。tokenizer将SQL文本分解为tokens,并将这些tokens逐个交给解析器。tokenizer是在tokenize.c文件中。
Parser
解析器根据令牌的上下文为其分配意义。SQLite的解析器是使用Lemon解析器生成器生成的。Lemon与YACC/BISON做同样的工作,但是它使用了不同的输入语法,因此不易出错。Lemon还生成一个可重入且线程安全的解析器。Lemon定义了非终端析构函数的概念,这样当遇到语法错误时它就不会泄漏内存。驱动Lemon并定义SQLite理解的SQL语言的语法文件可以在parse.y中找到。
因为Lemon是一个通常在开发机器上找不到的程序,所以Lemon的完整源代码(只有一个C文件)包含在SQLite发行版的“tool”子目录中。
Code Generator
在解析器将令牌组装到解析树中之后,代码生成器运行以分析解析器树并生成执行SQL语句工作的字节码。准备好的语句对象是此字节码的容器。代码生成器中有许多文件,包括:attach.c、auth.c、build.c、delete.c、expr.c、insert.c、pragma.c、select.c、trigger.c、update.c、vacuum.c、where.c、where code.c和whereexpr.c。在这些文件中,最严重的魔术发生在这里。expr.c处理表达式的代码生成。where*.c处理SELECT、UPDATE和DELETE语句中where子句的代码生成。attach.c、delete.c、insert.c、select.c、trigger.c update.c和vacuum.c文件处理同名SQL语句的代码生成。(根据需要,这些文件中的每一个都调用expr.c和where.c中的例程。)所有其他SQL语句都是用build.c编写的。auth.c文件实现了sqlite3_set_authorizer()的功能。
代码生成器,特别是*.c和select.c中的逻辑,有时称为查询规划器。对于任何特定的SQL语句,可能有数百、数千或数百万种不同的算法来计算答案。查询规划器是一个人工智能,它努力从数百万个选择中选择最好的算法。
Bytecode Engine
代码生成器创建的字节码程序由虚拟机运行。
虚拟机本身完全包含在单个源文件vdbe.c中。vdbe.h头文件定义了虚拟机与SQLite库和vdbeInt.h的其余部分之间的接口,后者定义了虚拟机本身私有的结构和接口。其他各种vdbe*.c文件是虚拟机的帮助程序。vdbeaux.c文件包含虚拟机使用的实用程序以及库中其他部分用来构造虚拟机程序的接口模块。vdbeapi.c文件包含到虚拟机的外部接口,如sqlite3_bind_int()和sqlite3_step()。单个值(字符串、整数、浮点数和blob)存储在名为“Mem”的内部对象中,该对象由vdbemem.c实现。
SQLite使用对C语言例程的回调来实现SQL函数。甚至内置的SQL函数也是这样实现的。大多数内置的SQL函数(例如:abs()、count()、substr()等等)都可以在func.c源文件中找到。日期和时间转换函数可在Date.c中找到。代码生成器直接将coalesce()和typeof()等函数作为字节码实现。
B-Tree
SQLite数据库使用B-tree.c源文件中的B树实现在磁盘上维护。数据库中的每个表和索引都使用单独的B树。所有的B树都存储在同一个磁盘文件中。文件格式的细节是稳定的和定义良好的,并保证向前移动时兼容。
B树子系统和SQLite库其余部分的接口由头文件B-tree.h定义。
Page Cache
B树模块以固定大小的页面从磁盘请求信息。默认页大小为4096字节,但可以是512到65536字节之间的任意两个幂。页面缓存负责读取、写入和缓存这些页面。页面缓存还提供回滚和原子提交抽象,并负责锁定数据库文件。B树驱动程序从页缓存请求特定页,并在页缓存想要修改页、提交或回滚更改时通知页缓存。页面缓存处理确保快速、安全、高效地处理请求的所有混乱细节。
主要页缓存实现位于pager.c文件中。WAL模式逻辑在单独的WAL.c中。内存缓存由pcache.c和pcache1.c文件实现。页面缓存子系统和SQLite其余部分之间的接口由头文件pager.h定义。
OS Interface
为了提供跨操作系统之间的可移植性,SQLite使用名为VFS的抽象对象。每个VFS提供打开、读取、写入和关闭磁盘上文件的方法,以及用于其他操作系统特定任务的方法,例如查找当前时间或获取随机性以初始化内置伪随机数生成器。SQLite目前为unix(在os-unix.c文件中)和Windows(在os-win.c文件中)提供vfse。
Utilities
内存分配、无大小写字符串比较例程、可移植的文本到数字转换例程和其他实用程序位于util.c中。解析器使用的符号表由hash.c中的哈希表维护。utf.c源文件包含Unicode转换子例程。SQLite在printf.c中有自己的printf()私有实现(带有一些扩展),在random.c中有自己的伪随机数生成器(PRNG)。