typedef struct sqlite3_vfs sqlite3_vfs; typedef void (*sqlite3_syscall_ptr)(void); struct sqlite3_vfs { int iVersion; /* Structure version number (currently 3) */ int szOsFile; /* Size of subclassed sqlite3_file */ int mxPathname; /* Maximum file pathname length */ sqlite3_vfs *pNext; /* Next registered VFS */ const char *zName; /* Name of this virtual file system */ void *pAppData; /* Pointer to application-specific data */ int (*xOpen)(sqlite3_vfs*, sqlite3_filename zName, sqlite3_file*, int flags, int *pOutFlags); int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); void (*xDlClose)(sqlite3_vfs*, void*); int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); int (*xSleep)(sqlite3_vfs*, int microseconds); int (*xCurrentTime)(sqlite3_vfs*, double*); int (*xGetLastError)(sqlite3_vfs*, int, char *); /* ** The methods above are in version 1 of the sqlite_vfs object ** definition. Those that follow are added in version 2 or later */ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); /* ** The methods above are in versions 1 and 2 of the sqlite_vfs object. ** Those below are for version 3 and greater. */ int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); /* ** The methods above are in versions 1 through 3 of the sqlite_vfs object. ** New fields may be appended in future versions. The iVersion ** value will increment whenever this happens. */ };
sqlite3_vfs 物件的實例定義了 SQLite 核心與底層作業系統之間的介面。物件名稱中的「vfs」代表「虛擬檔案系統」(virtual file system)。詳情請參閱VFS 文件。
VFS 介面有時會透過在其末尾新增方法來擴充。每次進行此類擴充時,iVersion 欄位都會遞增。 iVersion 值最初在 2007 年 9 月 4 日的 SQLite 3.5.0 版 中為 1,然後在 2010 年 7 月 21 日的 SQLite 3.7.0 版 中增加到 2,接著在 2011 年 4 月 12 日的 SQLite 3.7.6 版 中增加到 3。在未來的 SQLite 版本中,可能會將其他欄位附加到 sqlite3_vfs 物件,並且 iVersion 值可能會再次增加。請注意,由於疏忽,sqlite3_vfs 物件的結構在從 SQLite 3.5.9 版過渡到 2008 年 7 月 16 日的 3.6.0 版 時發生了變化,但 iVersion 欄位卻沒有增加。
szOsFile 欄位是此 VFS 使用的子類別 sqlite3_file 結構的大小。 mxPathname 是此 VFS 中路徑名稱的最大長度。
已註冊的 sqlite3_vfs 物件會保留在由 pNext 指標組成的鏈結串列中。sqlite3_vfs_register() 和 sqlite3_vfs_unregister() 介面以執行緒安全的方式管理此串列。sqlite3_vfs_find() 介面會搜尋此串列。應用程式程式碼和 VFS 實作都不應使用 pNext 指標。
pNext 欄位是 sqlite3_vfs 結構中 SQLite 唯一會修改的欄位。SQLite 只會在持有特定靜態互斥鎖時存取或修改此欄位。一旦物件已註冊,應用程式就不應修改 sqlite3_vfs 物件中的任何內容。
zName 欄位包含 VFS 模組的名稱。該名稱在所有 VFS 模組中必須是唯一的。
SQLite 保證 xOpen 的 zFilename 參數是指標 NULL 或從 xFullPathname() 取得的字串,並加上一個選用後綴。如果在 zFilename 參數中加入後綴,它將包含一個「-」字元,後跟不超過 11 個英數字元和/或「-」字元。SQLite 進一步保證,在呼叫 xClose() 之前,該字串將保持有效且不變。由於前一句的說明,sqlite3_file 可以安全地儲存指向檔案名的指標,如果它需要基於某些原因記住檔名。如果 xOpen 的 zFilename 參數是指標 NULL,則 xOpen 必須為檔案自行創建一個臨時名稱。每當 zFilename 參數為 NULL 時,flags 參數也將包含 SQLITE_OPEN_DELETEONCLOSE。
xOpen() 的 flags 參數包含在 sqlite3_open_v2() 的 flags 參數中設定的所有位元。或者,如果使用 sqlite3_open() 或 sqlite3_open16(),則 flags 至少包含 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE。如果 xOpen() 以唯讀方式開啟檔案,則它會設定 *pOutFlags 以包含 SQLITE_OPEN_READONLY。*pOutFlags 中的其他位元也可能被設定。
SQLite 也會根據所開啟的物件,將下列其中一個旗標新增至 xOpen() 呼叫:
檔案 I/O 實作可以使用物件類型旗標來改變其處理檔案的方式。例如,一個不關心崩潰恢復或回滾的應用程式可能會將開啟日誌檔案的操作變成無操作。寫入此日誌的操作也將是無操作,並且任何讀取日誌的嘗試都將返回 SQLITE_IOERR。或者,實作可能會識別資料庫檔案將以隨機順序執行頁面對齊的扇區讀寫,並相應地設置其 I/O 子系統。
SQLite 也可能會在 xOpen 方法中添加以下其中一個旗標:
SQLITE_OPEN_DELETEONCLOSE 旗標表示檔案在關閉時應該被刪除。對於暫存資料庫及其日誌、瞬態資料庫和子日誌,都會設定 SQLITE_OPEN_DELETEONCLOSE 旗標。
SQLITE_OPEN_EXCLUSIVE 旗標總是與 SQLITE_OPEN_CREATE 旗標一起使用,這兩個旗標分別直接對應於 POSIX open() API 的 O_EXCL 和 O_CREAT 旗標。 SQLITE_OPEN_EXCLUSIVE 旗標與 SQLITE_OPEN_CREATE 配對使用時,表示應始終建立檔案,如果檔案已存在則為錯誤。它*並非*用於指示以獨佔方式開啟檔案。
SQLite 會分配至少 szOsFile 位元組的記憶體來存放作為 xOpen 的第三個參數傳遞的 sqlite3_file 結構。 xOpen 方法不需要分配結構;它只需要填入即可。請注意,即使開啟失敗,xOpen 方法也必須將 sqlite3_file.pMethods 設置為有效的 sqlite3_io_methods 物件或 NULL。 無論 xOpen 呼叫成功或失敗,SQLite 都期望 sqlite3_file.pMethods 元素在 xOpen 返回後有效。
xAccess() 的 flags 參數可以是 SQLITE_ACCESS_EXISTS 來測試檔案是否存在,或是 SQLITE_ACCESS_READWRITE 來測試檔案是否可讀寫,或是 SQLITE_ACCESS_READ 來測試檔案是否至少可讀。SQLITE_ACCESS_READ 旗標實際上從未使用過,且在 SQLite 的內建 VFS 中也未實作。 檔案由第二個參數指定,可以是目錄。 如果成功,xAccess 方法會返回 SQLITE_OK,如果發生 I/O 錯誤或第二個參數中給出的檔案名稱不合法,則返回一些非零錯誤碼。 如果返回 SQLITE_OK,則會將非零或零寫入 *pResOut 以指示檔案是否可存取。
SQLite 總是會為輸出緩衝區 xFullPathname 分配至少 mxPathname+1 位元組。輸出緩衝區的確切大小也會作為參數傳遞給這兩個方法。如果輸出緩衝區不夠大,則應返回 SQLITE_CANTOPEN。由於 SQLite 將其視為致命錯誤,因此 vfs 實作應盡力透過將 mxPathname 設置為足夠大的值來防止這種情況發生。
xRandomness()、xSleep()、xCurrentTime() 和 xCurrentTimeInt64() 介面嚴格來說並非檔案系統的一部分,但為了完整性,它們被包含在 VFS 結構中。xRandomness() 函式嘗試將 nBytes 位元組的優質隨機數返回到 zOut 中。回傳值是實際獲得的隨機數位元組數。xSleep() 方法會使呼叫的執行緒至少休眠指定的微秒數。xCurrentTime() 方法以浮點值的形式返回目前日期和時間的儒略日數。xCurrentTimeInt64() 方法以整數形式返回儒略日數乘以 86400000(24 小時一天的毫秒數)。如果 xCurrentTimeInt64() 方法可用(如果 iVersion 為 2 或更大且函式指標不為 NULL),SQLite 將使用該方法獲取目前的日期和時間,如果 xCurrentTimeInt64() 不可用,則會使用 xCurrentTime() 方法。
SQLite 核心並未使用 xSetSystemCall()、xGetSystemCall() 和 xNestSystemCall() 介面。某些 VFS 提供這些可選介面是為了方便 VFS 程式碼的測試。透過使用其控制下的函式覆寫系統呼叫,測試程式可以模擬難以或不可能引發的錯誤和錯誤情況。可以覆寫的系統呼叫集合因 VFS 而異,即使是同一個 VFS 的不同版本也不相同。使用這些介面的應用程式必須準備好應對這些介面中的任何一個或全部為 NULL 的情況,或者它們的行為在不同版本之間發生變化。如果 VFS 的 iVersion 小於 3,應用程式不得嘗試存取這些方法中的任何一個。