Small. Fast. Reliable.
Choose any three.
SQLite的体系结构

介绍

本文档介绍了SQLite库的体系结构。对于那些想了解或修改SQLite内部工作原理的人来说,这里的信息很有用。

附近的图表显示了SQLite的主要组件以及它们如何互操作。下面的文本说明了各个组件的作用。

概述

SQLite的工作方式是将SQL文本编译为字节码,然后使用虚拟机运行该字节码。

sqlite3_prepare_v2()和相关接口充当SQL文本转换成字节码编译器。该sqlite3_stmt对象是单字节码程序实现一个SQL语句的容器。的sqlite3_step()接口传递一个字节码程序到虚拟机,并运行该程序,直到其完成,或将要返回的结果的行的形式,或命中了致命错误,或者被 中断

界面

尽管某些例程分散在其他文件中,但它们可以访问具有文件范围的数据结构,但是许多C语言接口都可以在源文件main.clegacy.cvdbeapi.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_

分词器

当要评估包含SQL语句的字符串时,首先将其发送到令牌生成器。令牌生成器将SQL文本分解为令牌,并将这些令牌一一交给解析器。标记器是手动编码在文件中的标记化c。

请注意,在此设计中,令牌生成器调用解析器。熟悉YACC和BISON的人可能习惯于以相反的方式进行操作-让解析器调用令牌生成器。但是,让分词器调用解析器会更好,因为可以使它成为线程安全的,并且运行速度更快。

解析器

解析器根据令牌的上下文为令牌分配含义。SQLite的解析器是使用 Lemon解析器生成器生成的。Lemon做的工作与YACC / BISON相同,但是它使用不同的输入语法,因此不容易出错。Lemon还生成可重入且线程安全的解析器。并且Lemon定义了非终端析构函数的概念,以便在遇到语法错误时不会泄漏内存。在parse.y中可以找到驱动Lemon并定义SQLite可以理解的SQL语言的语法文件。

因为Lemon是开发人员通常无法找到的程序,所以Lemonite的完整源代码(只有一个C文件)包含在“工具”子目录中的SQLite发行版中。

代码生成器

解析器将令牌组装成解析树后,代码生成器将运行以分析解析树并生成 执行SQL语句工作的字节码。在准备语句对象是此字节码的容器。有许多文件中的代码生成器,包括: attach.cauth.cbuild.cdelete.cexpr.cinsert.cpragma.cselect.ctrigger.cupdate.cvacuum.cwhere.cwherecode.cwhereexpr.c。在这些文件中,大多数严重的魔术都在其中发生。 expr.c处理表达式的代码生成。 where * .c处理SELECT,UPDATE和DELETE语句上WHERE子句的代码生成。该文件attach.cdelete.cinsert.cselect.ctrigger.c update.cvacuum.c处理代码生成具有相同名称的SQL语句。(这些文件中的每个文件根据需要在expr.cwhere.c中调用例程。)所有其他SQL语句均从build.c中进行编码。该auth.c文件实现sqlite3_set_authorizer()的功能 。

代码生成器,尤其是where * .cselect.c中的逻辑,有时被称为 查询计划器。对于任何特定的SQL语句,可能有成百上千,成千上万或数百万种不同的算法来计算答案。查询计划程序是一种AI,致力于从数百万种选择中选择最佳算法。

字节码引擎

由代码生成器创建的字节码程序由虚拟机运行。

虚拟机本身完全包含在单个源文件vdbe.c中。所述 vdbe.h头文件定义了虚拟机和SQLite库的其余部分之间的界面 vdbeInt.h其定义了私人虚拟机本身的结构和接口。其他各种vdbe * .c文件都是虚拟机的帮助程序。所述vdbeaux.c文件包含由所用的库的其余部分来构造VM程序在虚拟机和接口模块中使用的工具。所述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树

使用在btree.c源文件中找到的B树实现将SQLite数据库维护在磁盘上。数据库中的每个表和每个索引都使用单独的B树。所有B树都存储在同一磁盘文件中。该文件格式的细节是稳定和明确,并保证是向前兼容的移动。

B-tree子系统和其余SQLite库的接口由头文件btree.h定义。

页面缓存

B树模块以固定大小的页面从磁盘请求信息。默认的page_size为4096字节,但可以是512到65536字节之间的任意2的幂。页面缓存负责读取,写入和缓存这些页面。页面缓存还提供回滚和原子提交抽象,并负责锁定数据库文件。B树驱动程序从页面缓存中请求特定页面,并在想要修改页面或提交或回滚更改时通知页面缓存。页面缓存处理所有混乱的细节,以确保快速,安全,高效地处理请求。

主页面缓存实现位于 pager.c文件中。 WAL模式逻辑在单独的 wal.c中。内存中缓存由 pcache.cpcache1.c文件实现。页面缓存子系统和其余SQLite之间的接口由头文件pager.h定义。

操作系统界面

为了提供跨操作系统的可移植性,SQLite使用了称为VFS的抽象对象。每个VFS提供了用于打开,读取,写入和关闭磁盘上文件的方法,以及用于其他特定于OS的任务的方法,例如查找当前时间或获取随机性以初始化内置的伪随机数生成器。SQLite当前为UNIX(在os_unix.c 文件中)和Windows(在os_win.c文件中)提供VFS

实用工具

内存分配,无大小写的字符串比较例程,可移植的文本数字转换例程以及其他实用程序位于util.c中。解析器使用的符号表由hash.c中的哈希表维护。该utf.c源文件包含Unicode转换子程序。SQLite的有它自己的私有实现的 ()的printf(标有一些扩展)printf.c并在其自己的伪随机数生成器(PRNG)random.c

测试代码

源树的“ src /”文件夹中名称以test开头的文件 仅用于测试,不包含在库的标准内部版本中。