本文描述了SQLite库的架构。本文信息对哪些想要理解或修改SQLite内部工作内容的人非常有用。
附图展示了SQLite的主要组件以及他们是如何相互操作的。其下的文字解释了各个组件的角色。
SQLite 编译SQL文本为字节码bytecode, 然后使用虚拟机运行字节码来工作。
sqlite3_prepare_v2()以及相关接口扮演着编译器的角色,将SQL文本转换成字节码。 sqlite3_stmt 对象是一个容器。该容器用于包含一个实现某一SQL的字节码程序。 sqlite3_step() 接口向虚拟机传递字节码程序, 并执行字节码程序直到完成,或返回产生的一行结果,或碰到一个致命fatal错误, 或被打断。
大部分的C语言的接口在 main.c, legacy.c 和 vdbeapi.c 这些源文件中,尽管一些程序被分散在其他文件中,他们可以通过文件域访问数据结构。sqlite3_get_table()程序在 table.c 中实现.sqlite3_mprintf() 程序在 printf.c 中实现。sqlite3_complete() 接口在 tokenize.c 中. TCL Interface 在 tclsqlite.c 中实现.
为了避免命名冲突,SQLite库的所有的外部符号都使用 sqlite3 前缀。那些用于外部使用的(换句话说,那些符号形成了SQLite的API)符号增加下划线,因此以 sqlite3_ 开头。 扩展API有时候在下划线前增加扩展名;例如: sqlite3rbu_ 或 sqlite3session_。
解析器根据上下文为词赋予意思。SQLite的解析器使用Lemon parser generator生成。Lemon和YACC/BISON做同样的事情,但是它使用另一种不容易出错的输入语法。Lemon生成一个可重入的,线程安全的parser。Lemon定义了一个非终端析构的概念,因此在遇到语法错误时它不会内存泄漏。在parse.y中可以找到驱动Lemon的语法文件和SQLite理解SQL语言的定义的文件。 因为Lemon这个程序一般不会在开发机器上找到,所以Lemon完整的源代码(就一个C文件)被包含在SQLite分发的“tool”子目录中。
在解析器将词装配成解析树后,代码生成器开始分析解析树,生成执行SQL语句工作的字节码。prepared statement 对象是包含了这些字节码的容器。 代码生成器有很多文件,包含: attach.c, auth.c, build.c,delete.c, expr.c, insert.c, pragma.c, select.c, trigger.c, update.c, vacuum.c, where.c, wherecode.c, 和 whereexpr.c. 大部分重要的魔法发生在这些文件中。 expr.c 操纵着代码生成器的表达。 where.c* 操纵代码生成器处理SELECT,UPDATE和DELETE的WHERE从句。attach.c, delete.c, insert.c, select.c, trigger.c update.c, and vacuum.c 这几个文件操纵代码生成器处理和文件名同名的SQL语句。(所有这些文件必要时在expr.c 和 where.c中调用)所有其他SQL语句被编写在 build.c. auth.c 文件实现了 sqlite3_set_authorizer()的功能。
代码生成器,尤其时在where*.c 和 select.c中的逻辑,有时候被称为查询计划 query planner。对于任何具体的SQL语句,可能有成千上百个不同的算法来计算结果。查询计划query planner时一个力求从这么多算法中选择一个最好的算法的人工智能。
字节码程序被代码生成器生成,运行在虚拟机上。 虚拟机自身完整地包含在单独的 vdbe.c源文件中。vdbe.h头文件在虚拟机和剩余的SQLite库之间定义了接口, vdbeInt.h 定义的结构和接口是虚拟机自己私有的。其他几个vdbe*.c文件是虚拟机的助手。vdbeaux.c 文件包含虚拟机使用的有效工具和剩余SQLite库用于构建VM程序的接口模块。vdbeapi.c 文件包含虚拟机的扩展接口,如 sqlite3_bind_int() 和 sqlite3_step()。独立的值 (strings, integer, floating point numbers, and BLOBs) 被存储在由vdbemem.c实现,命名为“Mem”的内部对象中。
SQLite使用C语言程序的callbacks来实现SQL函数。即使内置的SQL函数也是这个方式实现。大部分内置SQL函数(如: abs(), count(), substr(), 等等) 能够在 func.c 源文件中找到。日期和时间转换函数在 date.c中找到。 一些函数如coalesce() 和 typeof() 由代码生成器直接生成字节码实现。
SQLite数据库使用B-tree来保存数据到磁盘,B-tree在源文件btree.c中实现。在数据库中的每个表和索引使用单独的B-tree。所有的B-tree存储在同一个磁盘文件中。文件格式file format 细节是稳定的、明确的、在更新中保证兼容性的。
B-tree子系统和其他SQLite库的交互接口在头文件btree.h中定义。
B-tree模块以固定大小的页向磁盘请求信息。默认的页大小是4096字节,也可以是512字节和65525字节之间任意的2的n次幂。页缓存负责读、写、缓存这些页。页缓存同时提供回滚和原子提交的抽象,同时负责锁定数据库文件。B-tree驱动从页缓存请求指定的页,当它想修改页、或提交、或回滚修改时,通知页缓存。页缓存确保快速、安全、高效地处理请求的所有混杂细节。 基本的页缓存在pager.c文件中实现。WAL mode逻辑在单独的wal.c中。内存缓存在 pcache.c 和 pcache1.c文件中实现。在pager.h头文件中,实现了页缓存子系统和SQLite库的其他系统交互的接口。
为了提供跨操作系统之间的可移植性,SQLite使用称为VFS的抽象对象。每个VFS都提供了对磁盘进行打开、读取、写入及关闭文件的方法,以及其他特定于操作系统的任务,例如查找当前时间或获取随机性来初始化内置伪随机数生成器。 SQLite目前为unix(在os_unix.c文件中)和Windows(在os_win.c文件中)提供VFS。
内存分配,字符串忽略大小写比较程序,可移植的文本到数字转换程序以及其他实用程序位于util.c中。解析器使用的符号表由hash.c中的哈希表维护。 utf.c源文件包含Unicode转换子例程。 SQLite在printf.c中有对printf()方法的私有实现(并进行了一些扩展),在random.c中有自己的伪随机数生成器(PRNG)。
在源文件“src /”文件夹中以test开头的文件仅用于测试使用,不包含在标准版本库中。
评论删除后,数据将无法恢复
评论(5)