介紹
這篇文檔描述了SQLite庫的架構(gòu)汛闸。如果想理解SQLite內(nèi)部原理,或者對它進(jìn)行修改,這篇文檔提供了有幫助的信息。
下圖展示了SQLite的主要組件和它們的協(xié)作方式粤策。后文解釋了這些組件的具體職責(zé)。
本文中各組件的原文譯文對照:
原文 | 譯文 |
---|---|
Interface | 接口 |
SQL Command Processor | SQL命令處理器 |
Virtual Machine | 虛擬機(jī) |
Tokenizer | 詞法分析器 |
Parser | 語法分析器 |
B-Tree | B樹 |
Pager | 頁緩存 |
OS Interface | OS接口 |
Utilities | 通用庫 |
Test Code | 測試代碼 |
概覽
SQLite的工作流程是將SQL文本編譯成字節(jié)碼误窖,然后在虛擬機(jī)上運(yùn)行這些字節(jié)碼叮盘。
sqlite3_prepare_v2()和相關(guān)的接口起到編譯器的作用,將SQL文本轉(zhuǎn)化為字節(jié)碼霹俺。sqlite3_stmt對象是一個字節(jié)碼容器柔吼,存儲了單條SQL語句所編譯出的字節(jié)碼。sqlite3_step()接口將字節(jié)碼程序傳給虛擬機(jī)吭服,執(zhí)行字節(jié)碼程序直到它完成嚷堡、返回結(jié)果集、遇到嚴(yán)重錯誤或被中斷(interrupted)艇棕。
接口
C語言接口主要在main.c蝌戒,legacy.c 和 vdbeapi.c中,也有一些接口分散在其他文件中沼琉,這是為了使它們能使用一些文件私有的數(shù)據(jù)結(jié)構(gòu)北苟。sqlite3_get_table()例程在table.c中,sqlite3_mprintf()在printf.c中打瘪,sqlite3_complete()在tokenize.c中友鼻,TCL Interface在tclsqlite.c中傻昙。
為避免名稱沖突,SQLite庫中的所有外部符號都以前綴sqlite3開頭彩扔。那些用于外部使用的符號妆档,也就是出現(xiàn)在SQLite API中的符號,會添加一個下劃線虫碉,從而以sqlite3_開頭贾惦。擴(kuò)展API有時會在下劃線之前添加擴(kuò)展名,例如:sqlite3rbu_或sqlite3session_敦捧。
詞法分析器
當(dāng)一條SQL語句要被編譯時须板,它首先被發(fā)送給詞法分析器。
詞法分析器將SQL文本分解成詞兢卵,然后將它一個個交給語法分析器习瑰。詞法分析器的文件是tokenize.c,其中的代碼是手工寫的秽荤。
注意此處的設(shè)計甜奄,是詞法分析器調(diào)用語法分析器。熟悉YACC或者BISON的人可能習(xí)慣于反過來——讓語法分析器調(diào)用詞法分析器窃款。前者更好贺嫂,因?yàn)樗梢宰龅骄€程安全,并且運(yùn)行地更快雁乡。
語法分析器
語法分析器根據(jù)詞的上下文賦予它語義。
SQLite的語法分析器通過Lemon LALR(1)生成糜俗。Lemon的功能和YACC踱稍、BISON類似,但是它所使用的輸入語法更不容易出錯悠抹。同時Lemon生成的語法分析器是可重入和線程安全的珠月。Lemon定義了“非終結(jié)符析構(gòu)器(non-terminal destructor)”的概念,因此它在遇到語法錯誤時不會泄露內(nèi)存楔敌。Lemon所需的語法文件是parse.y啤挎,其中定義了SQLite使用的SQL語法。
因?yàn)長emon很可能不在開發(fā)機(jī)器上卵凑,它完整的源代碼在SQLite的tool文件夾中庆聘,僅有一個C文件。
代碼生成器
語法分析器將詞轉(zhuǎn)化為語法樹勺卢,代碼生成器分析語法樹伙判,并且生成符合SQL功能的字節(jié)碼。
prepared statement對象是這段字節(jié)碼的容器黑忱。代碼生成器包含很多文件: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**垃帅。SQLite的魔法大多發(fā)生在這些文件中延届。
expr.c處理表達(dá)式的代碼生成,where.c處理SELECT贸诚,UPDATE方庭,DELETE語句的WHERE子句的代碼生成。attach.c酱固, delete.c械念,insert.c,select.c运悲,trigger.c龄减, update.c,和vacuum.c處理和文件名對應(yīng)的SQL語句的代碼生成班眯,其中每個文件都需要調(diào)用expr.c和where.c中的例程希停。其他所有的SQL語句都由build.c處理。auth.c*實(shí)現(xiàn)了sqlite3_set_authorizer()的功能署隘。
代碼生成器宠能,特別是where.c和select.c中的邏輯部分,有時被稱作查詢計劃器query planner磁餐。對于任何一條SQL語句违崇,可能有成百上千種不同的算法能得出結(jié)果。查詢計劃器是一個AI诊霹,盡力從其中選出最好的算法羞延。
字節(jié)碼引擎
生成器輸出的代碼最終由虛擬機(jī)來執(zhí)行。
虛擬機(jī)本身完全包含在單個文件中脾还,即vdbe.c文件肴楷。vdbe.h頭文件定義了其他SQLite庫與虛擬機(jī)之間的接口,而vdbeInt.h定義了虛擬機(jī)私有的數(shù)據(jù)結(jié)構(gòu)和接口荠呐。
剩下的多個vdbe.c文件是虛擬機(jī)的輔助代碼赛蔫。vdbeaux.c文件包含了虛擬機(jī)使用的通用庫砂客,以及其他庫用來構(gòu)造VM程序的接口模塊。vdbeapi.c文件包含了虛擬機(jī)的外部接口呵恢,比如sqlite3_bind_int()和 sqlite3_step()鞠值。單個值(字符串,整數(shù)渗钉,浮點(diǎn)數(shù)彤恶,二進(jìn)制數(shù)據(jù))存儲在一個內(nèi)部對象“Mem”中,該對象在vdbemem.c*實(shí)現(xiàn)鳄橘。
SQLite通過回調(diào)C語言來實(shí)現(xiàn)SQL的函數(shù)声离。甚至內(nèi)置的SQL函數(shù)也通過這種方式實(shí)現(xiàn)。大部分內(nèi)置SQL函數(shù)瘫怜,例如abs()术徊, count(),substr()等鲸湃,都寫在func.c文件中赠涮。日期時間轉(zhuǎn)換函數(shù)寫在date.c中。一些函數(shù)暗挑,例如coalesce() 和 typeof()直接被代碼生成器實(shí)現(xiàn)為字節(jié)碼笋除。
B樹
SQLite使用B樹結(jié)構(gòu)來維護(hù)磁盤上的數(shù)據(jù),B樹的實(shí)現(xiàn)在btree.c文件中炸裆。
數(shù)據(jù)庫中每個表和索引都使用單獨(dú)的B樹垃它。全部的B樹都存儲在同一個磁盤文件中。文件格式的規(guī)格是明確且穩(wěn)定的烹看,并且保證向前兼容嗤瞎。
B樹子系統(tǒng)對其他SQLite庫的接口定義在頭文件btree.h中。
頁緩存
B樹模塊要求磁盤上的信息具有固定的頁面大小听系。默認(rèn)的頁面大小(page_size)是4096字節(jié)虹菲,但是也可以設(shè)置為512到65536之間的2的整數(shù)冪靠胜。頁緩存負(fù)責(zé)頁面的讀寫和緩存。頁緩存也提供回滾和原子性提交的抽象毕源,并且負(fù)責(zé)對數(shù)據(jù)庫文件加鎖浪漠。
B樹模塊向頁緩存請求頁面,并且在修改頁面霎褐,提交或回滾時通知頁緩存址愿。頁緩存會處理大量的細(xì)節(jié),以確保請求被快速冻璃,安全响谓,高效地處理损合。
主要的頁緩存實(shí)現(xiàn)是在pager.c文件中,WAL模式的邏輯在單獨(dú)的wal.c中娘纷,內(nèi)存型緩存實(shí)現(xiàn)在pcache.c和pcache1.c文件中嫁审。頁緩存子系統(tǒng)對其他SQLite庫的接口定義在pager.h中。
OS接口
為了提供跨操作系統(tǒng)移植性赖晶,SQLite使用名為VFS的抽象對象律适。每個VFS提供對磁盤文件的打開、關(guān)閉以及讀寫方法遏插,以及其他特定于操作系統(tǒng)的功能捂贿,如獲得當(dāng)前時間,為偽隨機(jī)數(shù)生成器設(shè)置隨機(jī)種子等胳嘲。
SQLite目前對unix和Windows提供VFS厂僧,分別在os_unix.c和os_win.c文件中。
通用類
內(nèi)存分配胎围,大小寫不敏感的字符串比較例程吁系,可移植的字符串到數(shù)字轉(zhuǎn)換例程,以及其他通用庫位于util.c中白魂。
hash.c實(shí)現(xiàn)了哈希表結(jié)構(gòu)汽纤,在語法解析器中被用作符號表。utf.c源文件包含Unicode轉(zhuǎn)換的相關(guān)例程福荸。在printf.c中蕴坪,SQLite實(shí)現(xiàn)了自己私有的printf(),包含了一些拓展敬锐。在random.c中背传,SQLite也實(shí)現(xiàn)了自己的偽隨機(jī)數(shù)生成器。
測試代碼
在src文件夾中台夺,以test開頭的文件為測試代碼径玖,不被包含在標(biāo)準(zhǔn)庫版本中。