guest@blog.cmj.tw: ~/posts $

SQLite


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_mutexmallocBuiltinFuncpage 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_allclose_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