SQLite架构解析与关键函数

 SQLite 主页 - SQLite 中文

SQLite中的B-tree | SQlite源码分析 (huili.github.io)
数据库技术 - 随笔分类(第2页) - YY哥 - 博客园 (cnblogs.com)

SQLite权威指南 - 《SQLite权威指南》 - 书栈网 · BookStack

SQLite 教程 | 菜鸟教程 (runoob.com)

编程参考:

SQLite学习笔记

SQLite学习手册(目录) - OrangeAdmin - 博客园 (cnblogs.com)

 

一、SQLite 简介

SQLite是一个开源的嵌入式关系数据库,它在2000年由D. Richard Hipp发布,它的减少应用程序管理数据的开销,SQLite可移植性好,很容易使用,很小,高效而且可靠。
SQLite嵌入到使用它的应用程序中,它们共用相同的进程空间,而不是单独的一个进程。从外部看,它并不像一个RDBMS,但在进程内部,它却是完整的,自包含的数据库引擎。
嵌入式数据库的一大好处就是在你的程序内部不需要网络配置,也不需要管理。因为客户端和服务器在同一进程空间运行。SQLite 的数据库权限只依赖于文件系统,没有用户帐户的概念。SQLite 有数据库级锁定,没有网络服务器。它需要的内存,其它开销很小,适合用于嵌入式设备。你需要做的仅仅是把它正确的编译到你的程序。

SQLite 具有以下特点(SQLite’s Features and Philosophy)

1.1、零配置(Zero Configuration)
1.2、可移植(Portability):
它是运行在Windows,Linux,BSD,Mac OS X和一些商用Unix系统,比如Sun的Solaris,IBM的AIX,同样,它也可以工作在许多嵌入式操作系统下,比如QNX,VxWorks,Palm OS, Symbin和Windows CE。
1.3、Compactness:
SQLite是被设计成轻量级,自包含的。one header file, one library, and you’re relational, no external database server required
1.4、简单(Simplicity)
1.5、灵活(Flexibility)
1.6、可靠(Reliability):
SQLite的核心大约有3万行标准C代码,这些代码都是模块化的,很容易阅读。

二、架构(architecture)

SQLite采用了模块的设计,它由三个子系统,包括8个独立的模块构成。

SQLite拥有一个精致的、模块化的体系结构,并引进了一些独特的方法进行关系型数据库的管理。
它由被组织在 3 个子系统中的 8 个独立的模块组成,这些模块又被分割为两个部分: 前端解析系统和后端引擎,如图所示。

        前端预处理应用程序传递过来的SQL语句和SQLite命令,对获取的编码分析、优化,并转换为后端能够执行的SQLite内部字节编码。
前端可分为三个模块:<1> 标示分析;<2>语法分析;<3> 代码生成器。
        后端是用来解释字节编码程序的引擎,这个引擎做的才是真正的数据库处理工作。
后端部分由四个模块组成:<1>虚拟机(VM);<2> B/B+树;<3> 页面调度程序(pager);<4>操作系统交界面。
后端实现了 sqlite3_bind_*,sqlite3_setp,sqlite3_coloumn_*,sqlite3_reset和sqlite3_finalize API函数。
        这个模型将查询过程划分为几个不连续的任务,就像在流水线上工作一样。在体系结构栈的顶部编译查询语句,在中部执行它,在底部处理操作系统的存储和接口。

2.1、接口(Interface)
接口由SQLite C API组成,也就是说不管是程序、脚本语言还是库文件,最终都是通过它与SQLite交互的(我们通常用得较多的ODBC/JDBC最后也会转化为相应C API的调用)。

2.2、编译器(Compiler)
在编译器中,分词器(Tokenizer)和分析器(Parser)对SQL进行语法检查,然后把它转化为底层能更方便处理的分层的数据结构---语法树,然后把语法树传给代码生成器(code generator)进行处理。而代码生成器根据它生成一种针对SQLite的汇编代码,最后由虚拟机(Virtual Machine)执行。

2.3、虚拟机(Virtual Machine)
架构中最核心的部分是虚拟机,或者叫做虚拟数据库引擎(Virtual Database Engine,VDBE)。它和Java虚拟机相似,解释执行字节代码。VDBE的字节代码由128个操作码(opcodes)构成,它们主要集中在数据库操作。它的每一条指令都用来完成特定的数据库操作(比如打开一个表的游标)或者为这些操作栈空间的准备(比如压入参数)。总之,所有的这些指令都是为了满足SQL命令的要求(关于VM,后面会做详细介绍)。

2.4、后端(Back-End)
后端由B-树(B-tree),页缓存(page cache,pager)和操作系统接口(即系统调用)构成。B-tree和page cache共同对数据进行管理。B-tree的主要功能就是索引,它维护着各个页面之间的复杂的关系,便于快速找到所需数据。而pager的主要作用就是通过OS接口在B-tree和Disk之间传递页面。

 

二、编译器(Compiler)

2.1、分词器(Tokenizer)

 

接口把要执行的SQL语句传递给分词器 (Tokenizer) Tokenizer按照SQL的词法定义把它切分一个一个的词,并传递给分析器 (Parser) 进行语法分析。分词器是手工写的,主要在 Tokenizer.c 中实现。

 

2.2、分析器(Parser) 

SQLite的语法分析器是用 Lemon—— 一个开源的LALR(1)语法分析器的生成器,生成的文件为 parser.c。
一个简单的语法树:
 SELECT rowid, name, season FROM episodes WHERE rowid=1 LIMIT 1


 2.3、代码生成器(Code Generator)

代码生成器是SQLite中最庞大,最复杂的部分。它与Parser关系紧密,根据语法分析树 生成VDBE程序执行SQL语句的功能。
由诸多文件构成:trigger.c, update.c, insert.c, delete.c, select.c, where.c等文件。这些文件生成相应的VDBE程序指令,比如SELECT语句就由select.c生成。下面是一个读操作中打开表的代码的生成实现:

/* Generate code that will open a table for reading.
*/
void sqlite3OpenTableForReading(
  Vdbe *v,        /* Generate code into this VDBE */
  int iCur,       /* The cursor number of the table */
  Table *pTab     /* The table to be opened */
){
  sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
  sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
  VdbeComment((v, "# %s", pTab->zName));
  sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
}

 Sqlite3vdbeAddOp* 函数有三个参数:(1)VDBE实例(它将添加指令),(2)操作码(一条指令),(3)两个操作数。
Sqlite3vdbeAddOp0/1/2/3/4 


2.4、查询优化

代码生成器不仅负责生成代码,也负责进行查询优化。主要的实现位于where.c中,生成的WHERE语句块通常被其它模块共享,比如select.c,update.c以及delete.c。
这些模块调用 sqlite3WhereBegin() 开始WHERE语句块的指令生成,然后加入它们自己的VDBE代码返回,最后调用 sqlite3WhereEnd() 结束指令生成,如下:

 

三、SQLite数据库的存储机制

SQLite文件分析 (renrendoc.com)

SQLite文件格式分析_v102 - 百度文库 (baidu.com)

SQLite是一种轻量级的嵌入式数据库系统,被广泛应用于各种移动设备和桌面应用程序中。下面学习SQLite数据库的存储机制,并介绍其相对于其他数据库系统的优势。通过深入了解SQLite的存储机制,我们可以更好地理解它在实际应用中的表现和优势。

文件存储结构:SQLite数据库以单个文件的形式存储,这个文件包含了所有的表、索引、触发器等数据库对象。这种文件存储结构使得SQLite非常适合嵌入式设备和桌面应用程序,因为它不需要独立的服务器进程和额外的配置。

数据页:SQLite将数据分成固定大小的数据页(通常为4KB(4096)),每个数据页中包含了多个数据行。这种数据页的存储方式使得SQLite能够高效地处理大规模数据集,同时还能够减少磁盘IO的次数,提高数据库性能。

B树索引与表:B-Tree树用于存储索引, B+Tree树用于存储表。SQLite使用B树索引来加速数据的检索。B树索引以平衡树的形式存储索引数据,可以快速定位到特定的数据行。SQLite支持多种类型的索引,包括普通索引、唯一索引和全文索引等。
数据编码:SQLite使用变长整数编码、浮点数编码和字符串编码等方式来存储数据。这种数据编码方式既节省了存储空间,又提高了数据访问的效率。

B-tree和Pager

B-Tree使得VDBE可以在O(logN)下查询,插入和删除数据,以及O(1)下双向遍历结果集。B-Tree不会直接读写磁盘,它仅仅维护着页面(pages)之间的关系。当B-TREE需要页面或者修改页面时,它就会调用Pager。当修改页面时,pager保证原始页面首先写入日志文件,当它完成写操作时,pager根据事务状态决定如何做。B-tree不直接读写文件,而是通过page cache这个缓冲模块读写文件对于性能是有重要意义的(注:这和操作系统读写文件类似,在Linux中,操作系统的上层模块并不直接调用设备驱动读写设备,而是通过一个高速缓冲模块调用设备驱动读写文件,并将结果存到高速缓冲区)。

3.1、数据库文件格式(Database File Format)

数据库中所有的页面都按从1开始顺序标记。一个数据库由许多B-tree构成——每一个表和索引都有一个B-tree
注:索引采用B-tree,而表采用B+tree,这主要是表和索引的需求不同以及B-tree和B+tree的结构不同决定的:B+tree的所有叶子节点包含了全部关键字信息,而且可以有两种顺序查找——具体参见《数据结构》,严蔚敏。而B-tree更适合用来作索引)。所有表和索引的根页面都存储在sqlite_master表中。
数据库中第一个页面(page 1)有点特殊,page 1的前100个字节包含一个描述数据库文件的特殊的文件头。它包括库的版本,模式的版本,页面大小,编码等所有创建数据库时设置的参数。这个特殊的文件头的内容在btree.c中定义,page 1也是sqlite_master表的根页面。

3.2、页面重用及回收(Page Reuse and Vacuum )

SQLite利用一个空闲列表(free list)进行页面回收。当一个页面的所有记录都被删除时,就被插入到该列表。当运行VACUUM命令时,会清除free list,所以数据库会缩小,本质上它是在新的文件重新建立数据库,而所有使用的页在都被拷贝过去,而free list却不会,结果就是一个新的,变小的数据库。当数据库的autovacuum开启时,SQLite不会使用free list,而且在每一次commit时自动压缩数据库。

3.3、B-Tree记录(索引和表)

B-tree中页面由B-tree记录组成,也叫做payloads。每一个B-tree记录,或者payload有两个域:关键字域(key field)和数据域(data field)。Key field就是ROWID的值,或者数据库中表的关键字的值。从B-tree的角度,data field可以是任何无结构的数据。数据库的记录就保存在这些data fields中。B-tree的任务就是排序和遍历,它最需要就是关键字。Payloads的大小是不定的,这与内部的关键字和数据域有关,当一个payload太大不能存在一个页面内进便保存到多个页面。

B+Tree按关键字排序,所有的关键字必须唯一。表采用B+tree,内部页面不包含数据,如下:

 B+tree中根页面(root page)和内部页面(internal pages)都是用来导航的,这些页面的数据域都是指向下级页面的指针,仅仅包含关键字。所有的数据库记录都存储在叶子页面(leaf pages)内。在叶节点一级,记录和页面都是按照关键字的顺序的,所以B-tree可以水平方向遍历,时间复杂度为O(1)。

3.3.1  B-Tree 与 B+-Tree

SQLite 使用 B-Tree 存储索引,一个 B-Tree 对应一个索引;使用 B+-Tree 存储表,一个 B+-Tree 对应一个表。Tree 创建时就会为其分配一个根 Page(对应一个 Page Number),Page 标识了该 Tree,Tree 的根 Page 在 其生命周期内不会发生变更。

3.3.2 B-tree 索引

在基于 DBMSs 的外存储领域中,B-tree 在一个非常重要的索引结构,即索引采用B-treee按键所对应的值有序地存储记录集合。B-tree 是一种特殊的高度平衡树,n-ary, n > 2,所有叶子节点必须在统一层上。
实体(Entries[*])和搜索信息(如 key values)可存储在 B-tree 的内部节点和叶子节点。B-tree在所有的树操作(即插入、删除、搜索和下一个搜索)中,提供了近乎最佳的性能。
为了避免混淆,我在这里使用术语“entry”表示元组或记录。entry 由键和其它可选数据组成。 

B-tree页面由B-tree记录组成,B-tree记录也叫做payloads。每一个B-tree记录(payload)有两个域:关键字域(key field)和数据域(data field)。Key field就是rowid的值,或者数据库中表的关键字的值。
从B-tree的角度,data field可以是任何无结构的数据。数据库的记录就保存在这些data fields中。B-tree的任务就是排序和遍历,它最需要的是关键字。Payloads的大小是不定的,这与内部的关键字和数据域有关,当一个payload太大不能存在一个页面内,便保存到多个页面。

3.3.3 B+-Tree 表

B+-Tree 是 B-tree 的变种。B+Tree按关键字排序,所有的关键字必须唯一。表采用B+tree,内部页面不包含数据,如下:



B+tree中根页面(root page)和内部页面(internal pages)都是用来导航的,这些页面的数据域都是指向下级页面的指针,仅仅包含关键字。
所有的数据库记录都存储在叶子页面(leaf pages)内。在叶节点一级,记录和页面都是按照关键字的顺序的,所以B+tree可以水平方向遍历,时间复杂度为O(1)。
所有的实体 entries 都在叶子节点上,内部节点只包含有序的搜索信息(key values)和子节点指针。entries 是 (key value, data value) 对,按 key 值排序。

B-Tree 和 B+-Tree 的内部页节点的子指针数量,在一个预设的范围内[lower, upper](2 * lower >= upper),都是可变的。根页节点可能不符合这个规则,可能有任何数量的子指针即[0, upper]。所有的叶子节点都在同一个最低层,可以构成一个有序的链表。
upper = n +1 的 B+-Tree ,内部节点最多有n 个 keys,n+1 个子节点指针。对于任何内部节点,其对空间划为为 [<= Key(0), Key (0) < & <=Key(1), ..., Key (n - 1)<]。这样查询任何一条记录只需要遍历 O(log m) (m 是树中所有实体的数量)个节点

 

3.4、记录和域(Records and Fields)

位于叶节点页面的数据域记录(Payload) 由VDBE管理,数据库记录以二进制的形式存储,但有一定的数据格式。
在VDBE虚拟机引擎中创建记录,调用关系:sqlite3_step() -> sqlite3VdbeExec(操作码:OP_MakeRecord) ->  

  zHdr = (u8 *)pOut->z;
  zPayload = zHdr + nHdr;

记录(Payload)格式包括一个逻辑头(logical header)和一个数据区(data segment),header segment包括header的大小和一个数据类型数组,数据类型用来在data segment的数据的类型,如下:

 

 

sqlite3_column_type()函数返回第N列的值的数据类型. 具体的返回值如下:
#define SQLITE_INTEGER  1
#define SQLITE_FLOAT    2
#define SQLITE_TEXT     3
#define SQLITE_BLOB     4
#define SQLITE_NULL     5

sqlite3_column_count()函数返回结果集中包含的列数

 

3.5、层次数据组织(Hierarchical Data Organization)

从上往下,数据越来越无序,从下向上,数据越来越结构化.

3.6、B-Tree API

B-Tree模块有它自己的API,它可以独立于C API使用。另一个特点就是它支持事务。由pager处理的事务,锁和日志都是为B-tree服务的。根据功能可以分为以下几类:
2.6.1、访问和事务函数

sqlite3BtreeOpen: Opens a new database file. Returns a B-tree object.
sqlite3BtreeClose: Closes a database.
sqlite3BtreeBeginTrans: Starts a new transaction.
sqlite3BtreeCommit: Commits the current transaction.
sqlite3BtreeRollback: Rolls back the current transaction.
sqlite3BtreeBeginStmt: Starts a statement transaction.
sqlite3BtreeCommitStmt: Commits a statement transaction.
sqlite3BtreeRollbackStmt: Rolls back a statement transaction.

 

3.6.2、表函数

sqlite3BtreeCreateTable: Creates a new, empty B-tree in a database file.
sqlite3BtreeDropTable: Destroys a B-tree in a database file.
sqlite3BtreeClearTable: Removes all data from a B-tree, but keeps the B-tree intact.

 

3.6.3、游标函数(Cursor Functions)

sqlite3BtreeCursor: Creates a new cursor pointing to a particular B-tree.
sqlite3BtreeCloseCursor: Closes the B-tree cursor.
sqlite3BtreeFirst: Moves the cursor to the first element in a B-tree.
sqlite3BtreeLast: Moves the cursor to the last element in a B-tree.
sqlite3BtreeNext: Moves the cursor to the next element after the one it is currently pointing to.
sqlite3BtreePrevious: Moves the cursor to the previous element before the one it is currently pointing to.
sqlite3BtreeMoveto: Moves the cursor to an element that matches the key value passed  in as a parameter.

 

3.6.4、记录函数(Record Functions)

sqlite3BtreeDelete: Deletes the record that the cursor is pointing to.
sqlite3BtreeInsert: Inserts a new element in the appropriate place of the B-tree.
sqlite3BtreeKeySize: Returns the number of bytes in the key of the record that the cursor is pointing to.
sqlite3BtreeKey: Returns the key of the record the cursor is currently pointing to.
sqlite3BtreeDataSize: Returns the number of bytes in the data record that the cursor is currently pointing to.
sqlite3BtreeData: Returns the data in the record the cursor is currently pointing to.

 

3.6.5、配置函数(Configuration Functions)

sqlite3BtreeSetCacheSize: Controls the page cache size as well as the synchronous writes (as defined in the synchronous pragma).
sqlite3BtreeSetSafetyLevel: Changes the way data is synced to disk in order to increase
           or decrease how well the database resists damage due to OS crashes and power     failures.
           Level 1 is the same as asynchronous (no syncs() occur and there is a high probability of
           damage). This is the equivalent to pragma synchronous=OFF. Level 2 is the default. There
           is a very low but non-zero probability of damage. This is the equivalent to pragma
           synchronous=NORMAL. Level 3 reduces the probability of damage to near zero but with a
           write performance reduction. This is the equivalent to pragma synchronous=FULL.
sqlite3BtreeSetPageSize: Sets the database page size.
sqlite3BtreeGetPageSize: Returns the database page size.
sqlite3BtreeSetAutoVacuum: Sets the autovacuum property of the database.
sqlite3BtreeGetAutoVacuum: Returns whether the database uses autovacuum.
sqlite3BtreeSetBusyHandler: Sets the busy handler

 

3.7、实例分析
最后以sqlite3_open的具体实现结束本节的讨论(参见Version 3.6.10的源码):

由上图可以知道,SQLite的所有IO操作,最终都转化为操作系统的系统调用(一名话:DBMS建立在痛苦的OS之上)。同时也可以看到SQLite的实现非常的层次化,模块化,使得SQLite更易扩展,可移植性非常强。  

 附录 A:  源代码文件结构

 SQLite 文档 - SQLite 中文

 

Version 3.3.6源代码文件结构 

                                               ——整理: 2009-2-19 https://www.cnblogs.com/hustcat

文件名称

大小byte

函数

 

API部分

main.c

35414

SQLite Library的大部分接口

数据库连接对象sqlite3

预编译语句对象sqlite3_stmt

legacy.c

3734

sqlite3_exec()的实现

严格来说,不需要预编译语句对象,因为可以使用便捷包装器接口 sqlite3_exec() 或 sqlite3_get_table(),这些便捷包装器封装并隐藏了预编译语句对象。但是,需要了解预编译语句才能充分利用 SQLite。

table.c

5464

sqlite3_get_table() and sqlite3_free_table()的实现,

它们是sqlite3_exec的包装

 数据库连接和预编译语句对象由下面列出的少量 C/C++ 核心接口例程控制。

1. main.c::sqlite3_open()       //创建单个数据库连接
// 要运行 SQL 语句,应用程序执行以下步骤:

2. 使用 prepare.c::sqlite3_prepare() 创建一个预编译语句(vdbe字节程序)。
3. 通过调用“虚机接口”vdbeapi.c::sqlite3_step() 一次或多次来评估和执行预编译语句。
4. 对于查询,在两次调用 sqlite3_step() 之间通过调用 vdbeapi.c::sqlite3_column_*() 来提取结果。
5. 使用 vdbeapi.c::sqlite3_finalize() 销毁预编译语句。
6. sqlite3_close()          //关闭时销毁其数据库连接

preprare.c

17983

主要实现sqlite3_prepare_v2(): 

处理语句对象 sqlite3_stmt 的构造函数, 将SQL语句 编译成字节码程序:

语句(sqlite_stmt)会编译为个完整的VDBE程序,执行条单独的SQL命令

字节代码在内存中被封装成 sqlite3_stmt 对象

注意:sqlite3_prepare()工作于开始阶段,用于产生VDBE代码,它不参与执行。

所有SQL命令的VDBE程序,都可以通过EXPLAIN命令得到;

 SQLite 把 SQL 语句在运行时编译成字节码 bytecode,然后使用虚拟机,控制字节码的执行。

使用 sqlite3_prepare_v2() 将编译好的vdbe字节码程序,封装在 sqlite3_stmt 结构体中。

一个 sqlite3_stmt 结构体对应一个 SQL 语句,可使用 sqlite3_reset() 终结当前语句的执行并重置语句到初始状态、通过绑定函数(sqlite3_bind_*)和步进函数(sqlite3_step)实现编译字节码复用。不再使用的sqlite3_stmt 可使用 sqlite3_finalize 销毁。

 

 

 

 

分词器部分(Tokenizer)
Tokenizer把 SQL 文本拆分成多个标号,并把它们一个接一个地提交给解析器。在 Sqlite 中,Tokenizer 调用 Parser (在 YACC 和 BISON 中,Parser 主动调用 Tokenizer),是线程安全的并且运行的更快。

tokenize.c

14495

分词器的实现 sqlite3RunParser() -> sqlite3GetToken()

 

解析器部分(Parser),语法分析器

Parser 根据上下文,把语义给予 Tokenizer 产生的各个标号,并构建解析树。SQLite 中的 Parser 是使用 Lemon parser generator 生成的。Lemon 所做的工作与 YACC/BISON 相同,但使用一个出错少的输入语法。Tokenizer 也是使用 Lemon 产生的,可重入且线程安全。

 

parser.c

116917

分析器的实现,由Lemon实现 sqlite3Parser()

 

parser.h

6847

分析器内部定义的关键字  

 

 

 

 

 

代码生成器部分(Code Generator)

字节码产生器会分析 Parser 产生的解析树,产生 bytecode (存储在 prepared statement 中),进而把各个独立的字节码传递给虚拟机,由虚拟机控制字节码的执行,完成 SQL 语句所表示的行为。

 

update.c

23878

处理UPDATTE语句 sqlite3Update()

 

delete.c

21978

处理DELETE语句 sqlite3DeleteFrom()

 

insert.c

62026

处理INSERT语句  sqlite3Insert()

 

trigger.c

29065

处理TRIGGER语句 

 

attach.c

15941

处理ATTACHT 和DEATTACH语句

 文件 attach.cdelete.cinsert.cselect.ctrigger.cupdate.c, 和 vacuum.c 处理对应名称的语句的字节码产生(可能调用expr.c 和 where.c

where.c

75826

处理WHERE语句,
此外“查询优化

where*.c 处理SELECT, UPDATE 和 DELETE的 WHERE 子句的字节码生成;此外还有“查询优化”

select.c

112084

处理SELECT语句,sqlite3Select()
此外查询优化

代码产生器中,尤其是 where*.c 和 select.c 中的逻辑,有时被称为查询优化器 query planner

对于特定 SQL 语句,可能有成百上千种不同的算法去实现。query planner 可为特定的 SQL 语句选择最好的算法。

vacuum.c

11005

处理VACUUM语句

 

pragma.c

34289

处理PRAGMA命令

 

expr.c

73963

处理SQL语句中的表达式

 

auth.c

7496

主要实现 sqlite3_set_authorizer()

 

analyze.c

13149

实现ANALYZE命令

 

alter.c

18414

实现ALTER TABLE功能

 

build.c

104052

处理以下语法:

CREATE TABLE

DROP TABLE

CREATE INDEX

DROP INDEX

creating ID lists

BEGIN TRANSACTION

COMMIT

ROLLBACK

 其它语句都由 build.c 控制生成字节码

func.c

34335

实现SQL语句的函数语句

 

date.c

24031

与日期和时间转换有关的函数

 

虚拟机部分(Virtual Machine)       字节码引擎 Bytecode Engine:bytecode程序运行在字节码虚拟机上

vdbeapi.c

23300

虚拟机提供上层模块调用的API实现部分,
下面的几个C API直接和VDBE交互:
sqlite3_bind_*()
sqlite3_step()
sqlite3_reset()
sqlite3_column_*()
sqlite3_finalize()

vdbeapi.c 定义外部使用虚拟机的接口

sqlite3_step() 负责评估和执行预编译语句(VDBE字节程序)

 

vdbe.c

143552

虚拟机的主要实现部分
VDBE主处理函数: sqlite3VdbeExec(p)

 vdbe.c 虚拟机主体实现文件,调用关系如下
sqlite3_step() -> sqlite3VdbeExec()

vdbe.h

5309

定义了VDBE的接口,VdbeOp结构体(代表一条指令)

vdbe.h 虚拟与 SQLite 库之间的接口,

vdbeaux.c

58741

Vdbe.h的接口的实现
Sqlite3vdbeAddOp0/1/2/3/4 

 vdbeaux.c 包含被其它 SQLite library(如虚拟机和接口模块)使用的工具,用来构建 VM 程序

vdbeInt.h

17595

Vdbe.c的私有头文件,定义了VDBE常用的数据结构:

Cursor——虚拟机中使用的游标

Mem——vdbe在内部把所有的SQL值当作一个Mem数据结构来处理

Vdbe——虚拟机数据结构

 vdbeInt.h 定义虚拟机私有的接口和结构体

vdbemem.c

26375

操作”Mem”数据结构的函数

 vdbemem.c 各种数据类型(strings, integer, floating point numbers, and BLOBs) 在虚拟机中的存储对象,"Mem"

vdbefifo.c

2927

 

 vdbe*.c 定义各种虚拟机帮助函数

func.c SQLite 使用 C 历程实现的 SQL 函数,如abs(), count(), substr()
date.c 日期和时间函数
自定义函数,如coalesce() and typeof(),由字节码产生器直接实现,实现文件有:

 

 

 

 

B-Tree部分

btree.h

5260

头文件,定义了B-tree提供的操作接口:
sqlite3BtreeCreateTable()
sqlite3BtreeCreateIndex()
sqlite3BtreeClearTable()
sqlite3BtreeDropTable()
sqlite3BtreeInsert()
sqlite3BtreeDelete()
sqlite3BtreeUpdateMeta()

供VDBE调用,关系如下:
sqlite3_step() -> sqlite3VdbeExec(操作码:OP_Insert) ->  sqlite3BtreeInsert()
sqlite3_step() -> sqlite3VdbeExec(操作码:OP_Count) ->  sqlite3BtreeCount()

B-tree 模块以固定大小的页,向磁盘请求信息,在磁盘上,SQLite 使用 B-tree 维护数据(btree.c),一个表或索引对应一个独立 B-tree,所有的 B-tree 都在一个库文件中。

数据库文件格式 file format 定义十分稳定,具有非常好的兼容性。B-tree 子系统接口和 SQLite 库的其它接口在 btree.h 中。

btree.c

215570

B-Tree部分的主要实现,并定义了以下数据结构:

Btree——Btree handler

BtCursor——使用的游标

BtLock——锁

BtShared——包含了一个打开的数据库的所有信息

MemPage——文件在内存存放在该数据结构中

CellInfo ——btreeParseCellPtr () 函数使用之间从磁盘读出来的信息填充该字段 

struct Btree:一个数据库连接(sqlite3 指针)对应一个 struct Btree 对象,指向共享的struct BtShared 对象。

struct BtShared:一个对象代表一个数据库文件

sqlite3.mutex 为其各个字段的访问提供线程安全。如果开启共享缓存,使用 BtLock lock 字段控制首页的安全。

struct MemPage:页加载到内存中后,pager 会创建一个 MemPage 对象并把其前8个字节设置为0,使用磁盘上的原始页的内容信息填充该对象。通过 BtShared *pBt 互斥信号为其提供线程安全;DbPage *pDbPage 字段是控制页的具柄。

struct BtLock:存储在 BtShared.pLock 中的锁列表。使用表 BtShared.iTable 的根页打开游标时,向 BtShared.pLock列表添加一个 BtLock 对象,事物提交、回滚后或 Btree 关闭后移除该对象

BtCursor:一个指向 b-tree 中的特定记录 (entry) 的指针。通过 MemPage 和 MemPage 中记录的下标识别记录。一个 BtCursor 对应一个 Btree,BtCursor 列表存储在 BtShared 中;BtShared.mutex 为字段访问提供安全;
struct CellInfo:持有一个字段的信息,parseCellPtr() 函数使用之间从磁盘读出来的信息填充该字段

 

 

 

 

Pager部分

pager.h

4161

定义sqlite page cache子系统提供的接口

 默认为 4096 字节,域值为 {512,65536}。Page Cache 负责页的读、写和缓存,提供回滚和原子提交抽象,负责库文件锁操作。
B-tree 驱动器向 Page Cache 请求特定的页,并当它想修改页、提交或是回滚页时通知 Page Cache 。Page Cache 处理所有的细节,确保快速、安全且高效的完成请求。

pager.c

127490

Pager模块的主要实现,并定义了以下数据结构:

PgHdr——每一个内存中的页面的页面头

Pager——该模块中最重要的数据结构

PgHistory

 Page Cache 主要在 pager.c 文件中实现;WAL mode 逻辑在 wal.c 中;内存缓存由 pcache.c 和 pcache1.c 共同实现;page cache子系统和SQLite 其它模块之间的接口定义在 pager.h 中。B-tree 模块以固定大小的页,向磁盘请求信息,默认为 4096 字节,域值为 {512,65536}。Page Cache 负责页的读、写和缓存,提供回滚和原子提交抽象,负责库文件锁操作。

B-tree 驱动器向 Page Cache 请求特定的页,并当它想修改页、提交或是回滚页时通知 Page Cache 。Page Cache 处理所有的细节,确保快速、安全且高效的完成请求。

Page Cache 主要在 pager.c 文件中实现;WAL mode 逻辑在 wal.c 中;内存缓存由 pcache.c 和 pcache1.c 共同实现;page cache子系统和SQLite 其它模块之间的接口定义在 pager.h 中。

 

 

 

 

OS Interface部分

os.h

18355

定义了为上层模块提供的操作函数,并定义了以下数据结构:

OsFile——描述一个文件

IoMethod——OsFile所支持的操作函数(对所有架构都适用的OS Interface)

 SQLite 使用抽象对象 VFS,保证跨系统的移植性。VFS 提供的方法有:opening, read, writing, 和 closing 磁盘上的文件;
其它系统特定的任务,如 finding the current time, obtaining randomness to initialize the built-in pseudo-random number generator。

os.c

2866

对IoMethod中的函数的包装

 

os_win.c

42975

Windows平台下的OS Interface

 

os_unix.c

60831

Unix平台下的OS Interface

 

os_os2.c

28451

OS2平台下的OS Interface

 

 

 

 

 

实用工具部分

utf.c

20891

与UTF编码、Unicode 转换子程序

 

util.c

43575

一些实用函数,比如:

sqlite3Malloc(),sqlite3FreeX()

 

sqlite3.h

63873

SQLite的头文件,定义了提供给应用使用的API和数据结构。

 

sqliteInt.h

78886

定义了SQLite内部使用的接口和数据结构

 

printf.c

29556

主要实现与自定义 printf 有关函数

 

random.c

3078

伪随机数 PRNG 生成器

 

hash.c

11896

解析器使用的hash表

 

hash.h

4033

Hash 表头文件

 
posted @ 2024-09-26 11:30  suntroop  阅读(663)  评论(0)    收藏  举报