Code Review
來認真看一下 SQLite 的 source code:看的是 sqlite-amalgamation-3300100 這個版本。
shell.c
一開始透過 shell.c 來找到程式的入口點:int SQLITE_CDECL main 來執行一開始的 main function。透過 SQLITE_CDECL 來控制函數的 呼叫方式 :控制函數的參數的呼叫順序的約定。之後呼叫 3 個函數來控制 stdin 等設定:
- _setmode 在 Windows 設定將 stdin 的換行設定成 BINARY 模式 (僅 \n)。
- setvbuf 設定 stderr 不會有任何 buffer。
- isatty 判斷 stdin/stdout 是否顯示在 terminal 上。
接下來透過 main_init 將所有狀態初始化、透過 sqlite3_config 將大多數的設定初始化、初始化 signal handler、 接下來就是一個 for-loop 處理透過 stdin 近來的指令,將資料儲存在 ShellState 裡面:判斷檔名是否為 - 開頭。 接著執行 sqlite3_initialize 開始做初始化:sqlite3_mutex、malloc、BuiltinFunc、page cache。
之後透過 open_db 開啟 DB 檔案:透過 deduceDatabaseType 開啟真實體層的檔案並判斷型態、之後根據不同設定來使用不同 VFS 與設定來開啟 DB 檔案。舉例來說,在記憶體中開啟的 DB 則透過 sqlite3_open 開啟檔案:透過 sqlite3_api_routines 的 VFS 模組來呼叫 openDatabase:
- 初始化一個 sqlite3 實體 (pointer)
- 初始化 mutex
- 設定初始值
- 透過 sqlite3HashInit 初始化 hash 設定
- 透過 createCollation 設定 collating
- 透過 sqlite3ParseUri 處理 URI
- 透過 sqlite3BtreeOpen 開啟 BTree 的後端引擎、用 sqlite3SchemaGet 判斷使用哪個 schema
- 透過 sqlite3RegisterPerConnectionBuiltinFunctions 註冊 builtin functions
接著透過 process_sqliterc 來處理預設的 rc 檔案設定:讀取家目錄下的 .sqliterc 檔案、用 process_input 處理檔案。
最後用 second-pass 的方式在處理一次輸入的檔案:將設定檔寫入到 data 變數、開頭是 . 開頭則呼叫 do_meta_command 處理 SQL 指令、否則使用 shell_exec 執行 SQL 指令。之後透過 session_close_all 跟 close_db 關閉所有連線。
VFS
在 SQLite 中使用了 VFS 來做抽象畫的 I/O 操作:透過設定、註冊 sqlite3_vfs 相關的 I/O 操作,包含 open、delete、 access、fullpathname、dlopen、dlerror、dlsym、dlclose、randomness、sleep、currenttime、getlasterror、currenttimeint64、 setsystemcall、getsystemcall、nextsystemcall。可以分為三大類:基本的檔案 I/O、時間相關、syscall call 相關等。
BTree
在 SQLite 中有一個 Btree 的 structure 來紀錄
Meta Command
Shell Execute
在 shell_exec 的函數中透過以下幾個函數來執行 SQL:
- sqlite3_prepare_v2
- sqlite3_sql
- bind_prepared_stmt
- exec_prepared_stmt
- explain_data_delete
- eqp_render
- sqlite3_finalize
Close
當 SQLite 連線結束之後會呼叫 session_close_all 關閉所有 session:呼叫 session_close 關閉每一個 session、呼叫 sqlite3session_delete 清除 session 並清除記憶體中的資料。透過 sqlite3_preupdate_hook 將每一個 linked-list 中的 session 更新並移除。
真實底層呼叫的是 xPreUpdate:根據每個 session 用 sessionFindTable 找到更改的 table 名稱、透過 sessionPreupdateOneChange 來更新資料,其中會經過以下幾個步驟:
- sessionInitTable
- sessionTableInfo
- sqlite3_prepare_v2
- sqlite3_step
- sqlite3_finalize
- sessionGrowHash
- sessionPreupdateHash
- sessionPreupdateEqual