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”在对象名称中代表“虚拟文件系统”。请参阅VFS 文档以获取更多信息。
VFS 接口有时会通过在末尾添加新方法来扩展。每次发生此类扩展时,iVersion 字段都会递增。iVersion 值在 SQLite 3.5.0 版本(2007 年 9 月 4 日)中最初为 1,然后在 SQLite 3.7.0 版本(2010 年 7 月 21 日)中增加到 2,然后在 SQLite 3.7.6 版本(2011 年 4 月 12 日)中增加到 3。将来版本的 SQLite 可能会将其他字段附加到 sqlite3_vfs 对象,并且 iVersion 值可能会再次增加。请注意,由于疏忽,sqlite3_vfs 对象的结构在从 SQLite 3.5.9 版本到 3.6.0 版本(2008 年 7 月 16 日)的转换过程中发生了变化,但 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 必须为文件发明自己的临时名称。每当 xFilename 参数为 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 将为 TEMP 数据库及其日志、瞬态数据库和子日志设置。
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 预期无论 xOpen 调用的成功或失败如何,在 xOpen 返回后 sqlite3_file.pMethods 元素都将有效。
传递给 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 小时内毫秒数)。如果该方法可用(如果 iVersion 为 2 或更大且函数指针不为 NULL),SQLite 将使用 xCurrentTimeInt64() 方法获取当前日期和时间,如果 xCurrentTimeInt64() 不可用,则将回退到 xCurrentTime()。
xSetSystemCall()、xGetSystemCall() 和 xNestSystemCall() 接口不被 SQLite 核心使用。某些 VFS 提供了这些可选接口来促进 VFS 代码的测试。通过用其控制下的函数覆盖系统调用,测试程序可以模拟否则难以或无法诱发的故障和错误条件。可以覆盖的系统调用集因 VFS 而异,并且因同一 VFS 的不同版本而异。使用这些接口的应用程序必须做好准备,即任何或所有这些接口都可能为 NULL,或者其行为可能会从一个版本更改到下一个版本。如果 VFS 的 iVersion 小于 3,应用程序不得尝试访问任何这些方法。